IDEA-138441 Methods named like getters are wrongly treated as pure

don't track state for primitive get* methods
for reference-typed methods, track state only inside "if (getX() != null) ..."
flush dfa variables on non-pure getter-like calls
This commit is contained in:
peter
2015-05-18 17:02:51 +02:00
parent 069adff3dd
commit d27b4997b9
6 changed files with 45 additions and 17 deletions
@@ -650,10 +650,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return true;
}
// track "x" property state only inside "if (getX() != null) ..."
if (dfaLeft instanceof DfaVariableValue && ((DfaVariableValue)dfaLeft).containsCalls() && (!isNull(dfaRight) || !isNegated)) {
return true;
}
if (dfaLeft == dfaRight) {
if (dfaLeft instanceof DfaVariableValue && ((DfaVariableValue)dfaLeft).containsCalls()) {
return true;
}
return !isNegated;
}
@@ -27,7 +27,6 @@ package com.intellij.codeInspection.dataFlow.instructions;
import com.intellij.codeInspection.dataFlow.*;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.psi.*;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -126,7 +125,7 @@ public class MethodCallInstruction extends Instruction {
private boolean isPureCall() {
if (myTargetMethod == null) return false;
return ControlFlowAnalyzer.isPure(myTargetMethod) || PropertyUtil.isSimplePropertyGetter(myTargetMethod);
return ControlFlowAnalyzer.isPure(myTargetMethod);
}
@Nullable
@@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
import com.intellij.psi.util.PropertyUtil;
@@ -41,18 +42,21 @@ public class DfaExpressionFactory {
private static Condition<String> parseFalseGetters() {
try {
final Pattern pattern = Pattern.compile(Registry.stringValue("ide.dfa.getters.with.side.effects"));
return new Condition<String>() {
@Override
public boolean value(String s) {
return pattern.matcher(s).matches();
}
};
String regex = Registry.stringValue("ide.dfa.getters.with.side.effects").trim();
if (!StringUtil.isEmpty(regex)) {
final Pattern pattern = Pattern.compile(regex);
return new Condition<String>() {
@Override
public boolean value(String s) {
return pattern.matcher(s).matches();
}
};
}
}
catch (Exception e) {
LOG.error(e);
return Conditions.alwaysFalse();
}
return Conditions.alwaysFalse();
}
private final DfaValueFactory myFactory;
@@ -152,10 +156,11 @@ public class DfaExpressionFactory {
return (PsiVariable)target;
}
if (target instanceof PsiMethod) {
if (PropertyUtil.isSimplePropertyGetter((PsiMethod)target)) {
String qName = PsiUtil.getMemberQualifiedName((PsiMethod)target);
PsiMethod method = (PsiMethod)target;
if (PropertyUtil.isSimplePropertyGetter(method) && !(method.getReturnType() instanceof PsiPrimitiveType)) {
String qName = PsiUtil.getMemberQualifiedName(method);
if (qName == null || !FALSE_GETTERS.value(qName)) {
return (PsiMethod)target;
return method;
}
}
}
@@ -0,0 +1,21 @@
class A {
private String s;
private int next = 0;
public A(final String s) {
this.s = s;
}
private char getChar() {
return s.charAt(next++);
}
private void foo() {
char c = getChar();
if (c == 'a') {
if (getChar() == 'b') {
System.out.println("ab");
}
}
}
}
@@ -271,6 +271,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
public void testUnusedCallDoesNotMakeUnknown() { doTest(); }
public void testEmptyCallDoesNotMakeNullable() { doTest(); }
public void testGettersAndPureNoFlushing() { doTest(); }
public void testFalseGetters() { doTest(); }
public void testNotNullAfterDereference() { doTest(); }
@@ -294,7 +294,7 @@ ide.structural.navigation.visit.fields.description=Whether fields should be stop
ide.non.english.keyboard.layout.fix=false
ide.non.english.keyboard.layout.fix.description=Enables a fix for key codes with non-English keyboard layouts
ide.dfa.getters.with.side.effects=java\\.nio\\..*ByteBuffer\\.get.*
ide.dfa.getters.with.side.effects=
ide.dfa.getters.with.side.effects.description=A regex on qualified names of methods that look like getters but are not. For Constant Conditions & Exception inspection
ide.dfa.time.limit.online=1000