From 4b0262cbd0980d211a986932bc2154d0b55672a6 Mon Sep 17 00:00:00 2001 From: Jakub Zawadzki Date: Sun, 26 Feb 2017 16:22:02 +0100 Subject: [PATCH] Strings cannot be nil inspection --- resources/META-INF/gogland.xml | 3 + .../GoStringCannotBeNil.html | 21 +++++ .../GoStringCannotBeNilInspection.java | 90 +++++++++++++++++++ .../assignment-after.go | 6 ++ .../string-assigned-to-nil/assignment.go | 6 ++ .../comparison-after.go | 6 ++ .../string-assigned-to-nil/comparison.go | 6 ++ .../string-assigned-to-nil/nilVariable.go | 6 ++ .../tooManyValues-after.go | 5 ++ .../string-assigned-to-nil/tooManyValues.go | 5 ++ .../varDeclaration-after.go | 5 ++ .../string-assigned-to-nil/varDeclaration.go | 5 ++ .../GoStringCannotBeNilInspectionTest.java | 55 ++++++++++++ 13 files changed, 219 insertions(+) create mode 100644 resources/inspectionDescriptions/GoStringCannotBeNil.html create mode 100644 src/com/goide/inspections/GoStringCannotBeNilInspection.java create mode 100644 testData/inspections/string-assigned-to-nil/assignment-after.go create mode 100644 testData/inspections/string-assigned-to-nil/assignment.go create mode 100644 testData/inspections/string-assigned-to-nil/comparison-after.go create mode 100644 testData/inspections/string-assigned-to-nil/comparison.go create mode 100644 testData/inspections/string-assigned-to-nil/nilVariable.go create mode 100644 testData/inspections/string-assigned-to-nil/tooManyValues-after.go create mode 100644 testData/inspections/string-assigned-to-nil/tooManyValues.go create mode 100644 testData/inspections/string-assigned-to-nil/varDeclaration-after.go create mode 100644 testData/inspections/string-assigned-to-nil/varDeclaration.go create mode 100644 tests/com/goide/inspections/GoStringCannotBeNilInspectionTest.java diff --git a/resources/META-INF/gogland.xml b/resources/META-INF/gogland.xml index e8a4eac564..effeb15b7c 100644 --- a/resources/META-INF/gogland.xml +++ b/resources/META-INF/gogland.xml @@ -329,6 +329,9 @@ + diff --git a/resources/inspectionDescriptions/GoStringCannotBeNil.html b/resources/inspectionDescriptions/GoStringCannotBeNil.html new file mode 100644 index 0000000000..83ebb8c239 --- /dev/null +++ b/resources/inspectionDescriptions/GoStringCannotBeNil.html @@ -0,0 +1,21 @@ + + + + +Inspects for string assignation or comparision to nil. + + \ No newline at end of file diff --git a/src/com/goide/inspections/GoStringCannotBeNilInspection.java b/src/com/goide/inspections/GoStringCannotBeNilInspection.java new file mode 100644 index 0000000000..6ea0722280 --- /dev/null +++ b/src/com/goide/inspections/GoStringCannotBeNilInspection.java @@ -0,0 +1,90 @@ +package com.goide.inspections; + +import com.goide.GoConstants; +import com.goide.GoTypes; +import com.goide.psi.*; +import com.goide.psi.impl.GoElementFactory; +import com.goide.psi.impl.GoPsiImplUtil; +import com.goide.psi.impl.GoTypeUtil; +import com.intellij.codeInspection.*; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.stream.IntStream; + +public class GoStringCannotBeNilInspection extends GoInspectionBase { + public static final String QUICK_FIX_NAME = "Change to default value"; + private static final String DEFAULT_STRING = "\"\""; + private static final String PROBLEM_DESCRIPTION = "String cannot be nil"; + + @NotNull + @Override + protected GoVisitor buildGoVisitor(@NotNull ProblemsHolder holder, @NotNull LocalInspectionToolSession session) { + return new GoVisitor() { + + @Override + public void visitVarSpec(@NotNull GoVarSpec o) { + super.visitVarSpec(o); + + if (o.getVarDefinitionList() == null) return; + o.getVarDefinitionList().forEach(var -> check(var, var != null ? var.getValue() : null)); + } + + @Override + public void visitAssignmentStatement(@NotNull GoAssignmentStatement o) { + super.visitAssignmentStatement(o); + + if (o.getLeftHandExprList() == null) return; + List rightSide = o.getExpressionList(); + List leftSide = o.getLeftHandExprList().getExpressionList(); + if (leftSide == null || rightSide == null) return; + + IntStream.range(0, Math.min(leftSide.size(), rightSide.size())) + .forEach(i -> check(leftSide.get(i), rightSide.get(i))); + } + + @Override + public void visitBinaryExpr(@NotNull GoBinaryExpr o) { + super.visitBinaryExpr(o); + if (o.getOperator() == null || o.getOperator().getNode() == null) return; + IElementType type = o.getOperator().getNode().getElementType(); + if (type == GoTypes.EQ || type == GoTypes.NOT_EQ) { + check(o.getLeft(), o.getRight()); + check(o.getRight(), o.getLeft()); + } + } + + protected void check(GoTypeOwner var, GoExpression value) { + + if (var == null || value == null) return; + GoType varType = var.getGoType(null); + if (!GoTypeUtil.isString(varType)) return; + + if (value instanceof GoReferenceExpression && value.textMatches(GoConstants.NIL) + && GoPsiImplUtil.builtin(((GoReferenceExpression)value).resolve())) { + + holder.registerProblem(value, PROBLEM_DESCRIPTION, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + new GoChangeStringToDefaultValueQuickFix()); + } + } + }; + } + + private static class GoChangeStringToDefaultValueQuickFix extends LocalQuickFixBase { + public GoChangeStringToDefaultValueQuickFix() { + super(QUICK_FIX_NAME); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + if (element == null || !element.isValid()) return; + if (element instanceof GoExpression) { + element.replace(GoElementFactory.createExpression(project, DEFAULT_STRING)); + } + } + } +} diff --git a/testData/inspections/string-assigned-to-nil/assignment-after.go b/testData/inspections/string-assigned-to-nil/assignment-after.go new file mode 100644 index 0000000000..9d4ecc5f5b --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/assignment-after.go @@ -0,0 +1,6 @@ +package main + +func main() { + var var1, var2, var3 string; + var1, var2, var3 = "nil", "", "text" +} diff --git a/testData/inspections/string-assigned-to-nil/assignment.go b/testData/inspections/string-assigned-to-nil/assignment.go new file mode 100644 index 0000000000..8cafbcbee1 --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/assignment.go @@ -0,0 +1,6 @@ +package main + +func main() { + var var1, var2, var3 string; + var1, var2, var3 = "nil", nil, "text" +} diff --git a/testData/inspections/string-assigned-to-nil/comparison-after.go b/testData/inspections/string-assigned-to-nil/comparison-after.go new file mode 100644 index 0000000000..ebe5d38ade --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/comparison-after.go @@ -0,0 +1,6 @@ +package main + +func main() { + var var1 string; + "" == var1 +} diff --git a/testData/inspections/string-assigned-to-nil/comparison.go b/testData/inspections/string-assigned-to-nil/comparison.go new file mode 100644 index 0000000000..7c75e3d58e --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/comparison.go @@ -0,0 +1,6 @@ +package main + +func main() { + var var1 string; + nil == var1 +} diff --git a/testData/inspections/string-assigned-to-nil/nilVariable.go b/testData/inspections/string-assigned-to-nil/nilVariable.go new file mode 100644 index 0000000000..ef2998ef17 --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/nilVariable.go @@ -0,0 +1,6 @@ +package main + +func main() { + nil := "text" + var1 := nil +} diff --git a/testData/inspections/string-assigned-to-nil/tooManyValues-after.go b/testData/inspections/string-assigned-to-nil/tooManyValues-after.go new file mode 100644 index 0000000000..f2ddaf2d28 --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/tooManyValues-after.go @@ -0,0 +1,5 @@ +package main + +func main() { + var var1, var2 string = "nil", "", 5 + 13 +} \ No newline at end of file diff --git a/testData/inspections/string-assigned-to-nil/tooManyValues.go b/testData/inspections/string-assigned-to-nil/tooManyValues.go new file mode 100644 index 0000000000..9c4f623321 --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/tooManyValues.go @@ -0,0 +1,5 @@ +package main + +func main() { + var var1, var2 string = "nil", nil, 5 + 13 +} \ No newline at end of file diff --git a/testData/inspections/string-assigned-to-nil/varDeclaration-after.go b/testData/inspections/string-assigned-to-nil/varDeclaration-after.go new file mode 100644 index 0000000000..16d4599385 --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/varDeclaration-after.go @@ -0,0 +1,5 @@ +package main + +func main() { + var var1, var2, var3, var4 string = "nil", "", 5 + 13 +} diff --git a/testData/inspections/string-assigned-to-nil/varDeclaration.go b/testData/inspections/string-assigned-to-nil/varDeclaration.go new file mode 100644 index 0000000000..fe8bf27aeb --- /dev/null +++ b/testData/inspections/string-assigned-to-nil/varDeclaration.go @@ -0,0 +1,5 @@ +package main + +func main() { + var var1, var2, var3, var4 string = "nil", nil, 5 + 13 +} diff --git a/tests/com/goide/inspections/GoStringCannotBeNilInspectionTest.java b/tests/com/goide/inspections/GoStringCannotBeNilInspectionTest.java new file mode 100644 index 0000000000..02c6f96411 --- /dev/null +++ b/tests/com/goide/inspections/GoStringCannotBeNilInspectionTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2017 Sergey Ignatov, Alexander Zolotov, Florin Patan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.goide.inspections; + +import com.goide.SdkAware; +import com.goide.quickfix.GoQuickFixTestBase; + +@SdkAware +public class GoStringCannotBeNilInspectionTest extends GoQuickFixTestBase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(GoStringCannotBeNilInspection.class); + } + + public void testVarDeclaration() { + doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true); + } + + public void testAssignment() { + doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true); + } + + public void testTooManyValues() { + doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true); + } + + public void testComparison() { + doTest(GoStringCannotBeNilInspection.QUICK_FIX_NAME, true); + } + + public void testNilVariable() { + myFixture.testHighlighting(getTestName(true) + ".go"); + } + + @Override + protected String getBasePath() { + return "inspections/string-assigned-to-nil"; + } +}