Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Alioramus
Copy link

fixes #2144

@ignatov
Copy link
Contributor

ignatov commented Feb 19, 2017

@Alioramus Could you please sign https://www.jetbrains.com/agreements/cla/ first.

@Alioramus
Copy link
Author

Done.

@zolotov zolotov self-assigned this Feb 19, 2017
Copy link
Contributor

@zolotov zolotov left a 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(){


Copy link
Contributor

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){
Copy link
Contributor

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());
Copy link
Contributor

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();
Copy link
Contributor

@zolotov zolotov Feb 20, 2017

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();
Copy link
Contributor

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)){
Copy link
Contributor

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)];
Copy link
Contributor

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);
Copy link
Contributor

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() {
Copy link
Contributor

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));
Copy link
Contributor

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)){
Copy link
Contributor

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

){ – code style

Copy link
Author

@Alioramus Alioramus Feb 26, 2017

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.

Copy link
Contributor

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){

Copy link
Contributor

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;
Copy link
Contributor

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 {

Copy link
Contributor

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));
Copy link
Contributor

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");
}


Copy link
Contributor

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{
Copy link
Contributor

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 = "\"\"";
Copy link
Contributor

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";
Copy link
Contributor

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public?

@Alioramus
Copy link
Author

I hope it will be ok now and I apologise for so many mistakes.

Copy link
Contributor

@zolotov zolotov left a 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;
Copy link
Contributor

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;
Copy link
Contributor

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;
Copy link
Contributor

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why protected?

@zolotov
Copy link
Contributor

zolotov commented Feb 28, 2017

The whole inspection is questionable. According to Go language reference (https://golang.org/ref/spec#Assignability), you can assign nil only to a pointer, function, slice, map, channel, or interface type. Is it supposed to add the inspection for each type that is not pointer, function, slice, map, channel, or interface?

@zolotov
Copy link
Contributor

zolotov commented Feb 28, 2017

Rules for comparisons: https://golang.org/ref/spec#Comparison_operators

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Strings cannot be nil
3 participants