DFA: support value escaping on custom objects (IDEA-188303)

This commit is contained in:
Tagir Valeev
2018-04-25 17:43:43 +07:00
parent e863ce241a
commit 844b8cfa2c
4 changed files with 41 additions and 5 deletions
@@ -582,6 +582,9 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
}
DfaValue value = factory.createTypeValue(type, nullability);
if (!instruction.shouldFlushFields() && instruction.getContext() instanceof PsiNewExpression) {
value = factory.withFact(value, DfaFactType.LOCALITY, true);
}
return factory.withFact(value, DfaFactType.MUTABILITY, mutable);
}
LongRangeSet range = LongRangeSet.fromType(type);
@@ -24,9 +24,7 @@ import com.siyeh.ig.callMatcher.CallMatcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.*;
public class MethodCallInstruction extends Instruction {
@@ -198,8 +196,24 @@ public class MethodCallInstruction extends Instruction {
}
private boolean isPureCall() {
if (myTargetMethod == null) return false;
return ControlFlowAnalyzer.isPure(myTargetMethod) || SpecialField.findSpecialField(myTargetMethod) != null;
if (myTargetMethod != null) {
return ControlFlowAnalyzer.isPure(myTargetMethod) || SpecialField.findSpecialField(myTargetMethod) != null;
}
if (!(myContext instanceof PsiNewExpression)) return false;
PsiNewExpression newExpression = (PsiNewExpression)myContext;
if (newExpression.getArgumentList() == null || !newExpression.getArgumentList().isEmpty()) return false;
PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
if (classReference == null) return false;
PsiClass clazz = ObjectUtils.tryCast(classReference.resolve(), PsiClass.class);
if (clazz == null) return false;
Set<PsiClass> visited = new HashSet<>();
while (true) {
for (PsiMethod ctor : clazz.getConstructors()) {
if(ctor.getParameterList().isEmpty()) return ControlFlowAnalyzer.isPure(ctor);
}
clazz = clazz.getSuperClass();
if (clazz == null || !visited.add(clazz)) return false;
}
}
@Nullable
@@ -0,0 +1,18 @@
import java.util.*;
import org.jetbrains.annotations.*;
class ObjectLocality {
int x;
void test() {
ObjectLocality o = new ObjectLocality();
o.x = 5;
unknown();
<warning descr="Variable is already assigned to this value">o.x</warning> = 5;
o.unknown();
o.x = 5;
}
native void unknown();
}
@@ -609,4 +609,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
}
public void testMergedInitializerAndConstructor() { doTest(); }
public void testClassMethodsInlining() { doTest(); }
public void testObjectLocality() { doTest(); }
}