diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index d83f402a237e..71bd235d2a54 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -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); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java index 6c8785e29107..627ee565695b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java @@ -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 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 diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ObjectLocality.java b/java/java-tests/testData/inspection/dataFlow/fixture/ObjectLocality.java new file mode 100644 index 000000000000..0b3c60ec7118 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ObjectLocality.java @@ -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(); + o.x = 5; + o.unknown(); + o.x = 5; + } + + native void unknown(); +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java index b8dea85f11a5..78de20257fcd 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java @@ -609,4 +609,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { } public void testMergedInitializerAndConstructor() { doTest(); } public void testClassMethodsInlining() { doTest(); } + public void testObjectLocality() { doTest(); } }