-
Notifications
You must be signed in to change notification settings - Fork 572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strings cannot be nil inspection #2871
base: master
Are you sure you want to change the base?
Conversation
@Alioramus Could you please sign https://www.jetbrains.com/agreements/cla/ first. |
Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are required.
Also please cover with tests all exceptions that I found in the PR.
protected GoVisitor buildGoVisitor(@NotNull ProblemsHolder holder, @NotNull LocalInspectionToolSession session) { | ||
return new GoVisitor(){ | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code style
@Override | ||
public void visitVarSpec(@NotNull GoVarSpec o) { | ||
super.visitVarSpec(o); | ||
for(int i = 0; i < o.getExpressionList().size(); ++i){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use foreach on VarDefinitions instead and use getValue method to retrieve an expression
public void visitVarSpec(@NotNull GoVarSpec o) { | ||
super.visitVarSpec(o); | ||
for(int i = 0; i < o.getExpressionList().size(); ++i){ | ||
check(o.getVarDefinitionList().get(i).getGoType(null), o.getVarDefinitionList().get(i).getValue()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of possible NPEs
@Override | ||
public void visitAssignOp(@NotNull GoAssignOp o) { | ||
super.visitAssignOp(o); | ||
PsiElement[] right = o.getParent().getChildren(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks cryptic and non-reliable, you cannot say what children of parent are. if you want to visit some particular elements, you should visit them, not their children.
Also getParent might be null
, so yet another NPE here.
PsiElement[] right = o.getParent().getChildren(); | ||
if(right == null) return; | ||
|
||
List<GoExpression> left = ((GoLeftHandExprList)right[0]).getExpressionList(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possible ClassCastException and IndexOutOfBoundException
if(var == null || value == null) return; | ||
|
||
if(GoTypeUtil.isString(var)) { | ||
if(value.getText().equals(GoConstants.NIL)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if variable's text is nil
, it doesn't mean that it's really nil
. It can be reference to some other variable: https://play.golang.org/p/AcZdk3hfzU
use com.goide.psi.impl.GoExpressionUtil#isNil
instead
|
||
for(int i = 0; i < left.size(); ++i){ | ||
GoExpression var = left.get(i); | ||
PsiElement value = right[right.length - (left.size() - i)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OutOfBoundsException
PsiElement value = right[right.length - (left.size() - i)]; | ||
|
||
if(value instanceof GoExpression){ | ||
check(var.getGoType(null), (GoExpression)value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NPE on var
if(GoTypeUtil.isString(var)) { | ||
if(value.getText().equals(GoConstants.NIL)){ | ||
|
||
holder.registerProblem(value, PROBLEM_DESC, new LocalQuickFix() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not shorten names, PROBLEM_DESCRIPTION is just fine
|
||
@Override | ||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { | ||
value.replace(GoElementFactory.createExpression(project, DEFAULT_STRING)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memory leak on value
, element from ProblemDescriptor should be used
PsiReference valueRef = value.getReference(); | ||
if(valueRef == null) return; | ||
PsiElement valueResolved = valueRef.resolve(); | ||
if(value.textMatches(GoConstants.NIL) && valueResolved != null && GoPsiImplUtil.builtin(valueResolved)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
com.goide.psi.impl.GoExpressionUtil#isNil
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
){
– code style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zolotov What do you mean by com.goide.psi.impl.GoExpressionUtil#isNil? I havent seen isNil there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I looked at the wrong repo. Ok then, it's ok to have this here. You can optimize it though:
- check that value is GoReferenceExpressions, other elements cannot be resolved to
nil
- check text first, it's much simpler than resolving
boolean isNil = value instanceof GoReferenceExpression && value.textMatches(GoConstants.NIL) && GoPsiImplUtil.builtin(((GoReferenceExpression)value).resolve())
} | ||
|
||
protected void check(GoTypeOwner var, GoExpression value){ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code style
|
||
protected void check(GoTypeOwner var, GoExpression value){ | ||
|
||
if(var == null || value == null) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if(
code style.
Please just run code formatting
} | ||
|
||
public static class GoChangeStringToDefaultValueQuickFix extends LocalQuickFixBase { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code style
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { | ||
PsiElement element = descriptor.getPsiElement(); | ||
if(element == null) return; | ||
element.replace(GoElementFactory.createExpression(project, DEFAULT_STRING)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
element
can be invalid at this point. Also you don't check what element it is. E.g. in case of batch
inspection mode that was run on injected text, you'll get a file here as an element, I don't think you want to replace file with ""
myFixture.testHighlighting(getTestName(true) + ".go"); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code style
import java.util.List; | ||
import java.util.stream.IntStream; | ||
|
||
public class GoStringCannotBeNilInspection extends GoInspectionBase{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code style
|
||
public class GoStringCannotBeNilInspection extends GoInspectionBase{ | ||
public static final String QUICK_FIX_NAME = "Change to default value"; | ||
public static final String DEFAULT_STRING = "\"\""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public?
public class GoStringCannotBeNilInspection extends GoInspectionBase{ | ||
public static final String QUICK_FIX_NAME = "Change to default value"; | ||
public static final String DEFAULT_STRING = "\"\""; | ||
public static final String PROBLEM_DESCRIPTION = "String cannot be nil"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public?
}; | ||
} | ||
|
||
public static class GoChangeStringToDefaultValueQuickFix extends LocalQuickFixBase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public?
I hope it will be ok now and I apologise for so many mistakes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good, just make sure that inspection file is "green" and IDE doesn't complain on it.
public void visitVarSpec(@NotNull GoVarSpec o) { | ||
super.visitVarSpec(o); | ||
|
||
if (o.getVarDefinitionList() == null) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
always false
public void visitAssignmentStatement(@NotNull GoAssignmentStatement o) { | ||
super.visitAssignmentStatement(o); | ||
|
||
if (o.getLeftHandExprList() == null) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
always false
if (o.getLeftHandExprList() == null) return; | ||
List<GoExpression> rightSide = o.getExpressionList(); | ||
List<GoExpression> leftSide = o.getLeftHandExprList().getExpressionList(); | ||
if (leftSide == null || rightSide == null) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
always false
} | ||
} | ||
|
||
protected void check(GoTypeOwner var, GoExpression value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why protected?
The whole inspection is questionable. According to Go language reference (https://golang.org/ref/spec#Assignability), you can assign |
Rules for comparisons: https://golang.org/ref/spec#Comparison_operators |
fixes #2144