Skip to content

Commit b692011

Browse files
author
Jakub Zawadzki
committed
Strings cannot be nil inspection
1 parent eb5fc24 commit b692011

File tree

13 files changed

+221
-0
lines changed

13 files changed

+221
-0
lines changed

Diff for: resources/META-INF/gogland.xml

+3
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@
329329
<localInspection language="go" displayName="Multiple packages in directory declaration" groupPath="Go"
330330
groupName="General" enabledByDefault="true" level="ERROR"
331331
implementationClass="com.goide.inspections.GoMultiplePackagesInspection"/>
332+
<localInspection language="go" displayName="String cannot be nil" groupPath="Go"
333+
groupName="General" enabledByDefault="true" level="ERROR"
334+
implementationClass="com.goide.inspections.GoStringCannotBeNilInspection"/>
332335
<localInspection language="go" displayName="Usage of cgo in tests is not supported" groupPath="Go"
333336
groupName="General" enabledByDefault="true" level="ERROR"
334337
implementationClass="com.goide.inspections.GoCgoInTestInspection"/>
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!--
2+
~ Copyright 2013-2017 Sergey Ignatov, Alexander Zolotov, Florin Patan
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
17+
<html>
18+
<body>
19+
Inspects for string assignation or comparision to nil.
20+
</body>
21+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.goide.inspections;
2+
3+
import com.goide.GoConstants;
4+
import com.goide.GoTypes;
5+
import com.goide.psi.*;
6+
import com.goide.psi.impl.GoElementFactory;
7+
import com.goide.psi.impl.GoPsiImplUtil;
8+
import com.goide.psi.impl.GoTypeUtil;
9+
import com.intellij.codeInspection.*;
10+
import com.intellij.openapi.project.Project;
11+
import com.intellij.psi.PsiElement;
12+
import com.intellij.psi.PsiReference;
13+
import com.intellij.psi.tree.IElementType;
14+
import org.jetbrains.annotations.NotNull;
15+
16+
import java.util.List;
17+
import java.util.stream.IntStream;
18+
19+
public class GoStringCannotBeNilInspection extends GoInspectionBase{
20+
public static final String QUICK_FIX_NAME = "Change to default value";
21+
public static final String DEFAULT_STRING = "\"\"";
22+
public static final String PROBLEM_DESCRIPTION = "String cannot be nil";
23+
24+
@NotNull
25+
@Override
26+
protected GoVisitor buildGoVisitor(@NotNull ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
27+
return new GoVisitor(){
28+
29+
@Override
30+
public void visitVarSpec(@NotNull GoVarSpec o) {
31+
super.visitVarSpec(o);
32+
33+
if(o.getVarDefinitionList() == null) return;
34+
o.getVarDefinitionList().forEach(var -> check(var, var != null ? var.getValue() : null));
35+
}
36+
37+
@Override
38+
public void visitAssignmentStatement(@NotNull GoAssignmentStatement o) {
39+
super.visitAssignmentStatement(o);
40+
41+
if(o.getLeftHandExprList() == null) return;
42+
List<GoExpression> rightSide = o.getExpressionList();
43+
List<GoExpression> leftSide = o.getLeftHandExprList().getExpressionList();
44+
if(leftSide == null || rightSide == null) return;
45+
46+
IntStream.range(0 , Math.min(leftSide.size(), rightSide.size()))
47+
.forEach(i -> check(leftSide.get(i), rightSide.get(i)));
48+
}
49+
50+
@Override
51+
public void visitBinaryExpr(@NotNull GoBinaryExpr o) {
52+
super.visitBinaryExpr(o);
53+
if(o.getOperator() == null || o.getOperator().getNode() == null) return;
54+
IElementType type = o.getOperator().getNode().getElementType();
55+
if(type == GoTypes.EQ || type == GoTypes.NOT_EQ){
56+
check(o.getLeft(), o.getRight());
57+
check(o.getRight(), o.getLeft());
58+
}
59+
}
60+
61+
protected void check(GoTypeOwner var, GoExpression value){
62+
63+
if(var == null || value == null) return;
64+
GoType varType = var.getGoType(null);
65+
if(!GoTypeUtil.isString(varType)) return;
66+
PsiReference valueRef = value.getReference();
67+
if(valueRef == null) return;
68+
PsiElement valueResolved = valueRef.resolve();
69+
if(value.textMatches(GoConstants.NIL) && valueResolved != null && GoPsiImplUtil.builtin(valueResolved)){
70+
holder.registerProblem(value, PROBLEM_DESCRIPTION, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
71+
new GoChangeStringToDefaultValueQuickFix());
72+
}
73+
}
74+
};
75+
}
76+
77+
public static class GoChangeStringToDefaultValueQuickFix extends LocalQuickFixBase {
78+
79+
public GoChangeStringToDefaultValueQuickFix() {
80+
super(QUICK_FIX_NAME);
81+
}
82+
83+
@Override
84+
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
85+
PsiElement element = descriptor.getPsiElement();
86+
if(element == null) return;
87+
element.replace(GoElementFactory.createExpression(project, DEFAULT_STRING));
88+
}
89+
}
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
func main() {
4+
var var1, var2, var3 string;
5+
var1, var2, var3 = "nil", "", "text"
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
func main() {
4+
var var1, var2, var3 string;
5+
var1, var2, var3 = "nil", <error descr="String cannot be nil"><caret>nil</error>, "text"
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
func main() {
4+
var var1 string;
5+
"" == var1
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
func main() {
4+
var var1 string;
5+
<error descr="String cannot be nil"><caret>nil</error> == var1
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
func main() {
4+
nil := "text"
5+
var1 := nil
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
func main() {
4+
var var1, var2 string = "nil", "", 5 + 13
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
func main() {
4+
var var1, var2 string = "nil", <error descr="String cannot be nil"><caret>nil</error>, 5 + 13
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
func main() {
4+
var var1, var2, var3, var4 string = "nil", "", 5 + 13
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
func main() {
4+
var var1, var2, var3, var4 string = "nil", <error descr="String cannot be nil"><caret>nil</error>, 5 + 13
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2013-2017 Sergey Ignatov, Alexander Zolotov, Florin Patan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.goide.inspections;
18+
19+
20+
import com.goide.SdkAware;
21+
import com.goide.quickfix.GoQuickFixTestBase;
22+
23+
@SdkAware
24+
public class GoStringCannotBeNilInspectionTest extends GoQuickFixTestBase{
25+
26+
@Override
27+
protected void setUp() throws Exception {
28+
super.setUp();
29+
myFixture.enableInspections(GoStringCannotBeNilInspection.class);
30+
}
31+
32+
public void testVarDeclaration() {
33+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
34+
}
35+
36+
public void testAssignment() {
37+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
38+
}
39+
40+
public void testTooManyValues() {
41+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
42+
}
43+
44+
public void testComparison() {
45+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
46+
}
47+
48+
public void testNilVariable() {
49+
myFixture.testHighlighting(getTestName(true) + ".go");
50+
}
51+
52+
53+
@Override
54+
protected String getBasePath() {
55+
return "inspections/string-assigned-to-nil";
56+
}
57+
}

0 commit comments

Comments
 (0)