mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
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:
+5
-3
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -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
|
||||
|
||||
+16
-11
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user