Skip to content

Commit 4b0262c

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

File tree

13 files changed

+219
-0
lines changed

13 files changed

+219
-0
lines changed

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"/>
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.tree.IElementType;
13+
import org.jetbrains.annotations.NotNull;
14+
15+
import java.util.List;
16+
import java.util.stream.IntStream;
17+
18+
public class GoStringCannotBeNilInspection extends GoInspectionBase {
19+
public static final String QUICK_FIX_NAME = "Change to default value";
20+
private static final String DEFAULT_STRING = "\"\"";
21+
private static final String PROBLEM_DESCRIPTION = "String cannot be nil";
22+
23+
@NotNull
24+
@Override
25+
protected GoVisitor buildGoVisitor(@NotNull ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
26+
return new GoVisitor() {
27+
28+
@Override
29+
public void visitVarSpec(@NotNull GoVarSpec o) {
30+
super.visitVarSpec(o);
31+
32+
if (o.getVarDefinitionList() == null) return;
33+
o.getVarDefinitionList().forEach(var -> check(var, var != null ? var.getValue() : null));
34+
}
35+
36+
@Override
37+
public void visitAssignmentStatement(@NotNull GoAssignmentStatement o) {
38+
super.visitAssignmentStatement(o);
39+
40+
if (o.getLeftHandExprList() == null) return;
41+
List<GoExpression> rightSide = o.getExpressionList();
42+
List<GoExpression> leftSide = o.getLeftHandExprList().getExpressionList();
43+
if (leftSide == null || rightSide == null) return;
44+
45+
IntStream.range(0, Math.min(leftSide.size(), rightSide.size()))
46+
.forEach(i -> check(leftSide.get(i), rightSide.get(i)));
47+
}
48+
49+
@Override
50+
public void visitBinaryExpr(@NotNull GoBinaryExpr o) {
51+
super.visitBinaryExpr(o);
52+
if (o.getOperator() == null || o.getOperator().getNode() == null) return;
53+
IElementType type = o.getOperator().getNode().getElementType();
54+
if (type == GoTypes.EQ || type == GoTypes.NOT_EQ) {
55+
check(o.getLeft(), o.getRight());
56+
check(o.getRight(), o.getLeft());
57+
}
58+
}
59+
60+
protected void check(GoTypeOwner var, GoExpression value) {
61+
62+
if (var == null || value == null) return;
63+
GoType varType = var.getGoType(null);
64+
if (!GoTypeUtil.isString(varType)) return;
65+
66+
if (value instanceof GoReferenceExpression && value.textMatches(GoConstants.NIL)
67+
&& GoPsiImplUtil.builtin(((GoReferenceExpression)value).resolve())) {
68+
69+
holder.registerProblem(value, PROBLEM_DESCRIPTION, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
70+
new GoChangeStringToDefaultValueQuickFix());
71+
}
72+
}
73+
};
74+
}
75+
76+
private static class GoChangeStringToDefaultValueQuickFix extends LocalQuickFixBase {
77+
public GoChangeStringToDefaultValueQuickFix() {
78+
super(QUICK_FIX_NAME);
79+
}
80+
81+
@Override
82+
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
83+
PsiElement element = descriptor.getPsiElement();
84+
if (element == null || !element.isValid()) return;
85+
if (element instanceof GoExpression) {
86+
element.replace(GoElementFactory.createExpression(project, DEFAULT_STRING));
87+
}
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,55 @@
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+
import com.goide.SdkAware;
20+
import com.goide.quickfix.GoQuickFixTestBase;
21+
22+
@SdkAware
23+
public class GoStringCannotBeNilInspectionTest extends GoQuickFixTestBase {
24+
25+
@Override
26+
protected void setUp() throws Exception {
27+
super.setUp();
28+
myFixture.enableInspections(GoStringCannotBeNilInspection.class);
29+
}
30+
31+
public void testVarDeclaration() {
32+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
33+
}
34+
35+
public void testAssignment() {
36+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
37+
}
38+
39+
public void testTooManyValues() {
40+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
41+
}
42+
43+
public void testComparison() {
44+
doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true);
45+
}
46+
47+
public void testNilVariable() {
48+
myFixture.testHighlighting(getTestName(true) + ".go");
49+
}
50+
51+
@Override
52+
protected String getBasePath() {
53+
return "inspections/string-assigned-to-nil";
54+
}
55+
}

0 commit comments

Comments
 (0)