From 7ec424fabd07282e273f2b74094d905dbfd2104c Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 2 Apr 2018 12:58:08 +0300 Subject: [PATCH] Java: Handle chained assignment of fields in class initializer (IDEA-188872) --- .../defUse/DefUseInspectionBase.java | 14 +++++++++++++ .../defUse/ChainedFieldInitializer.java | 21 +++++++++++++++++++ .../java/codeInspection/DefUseTest.java | 1 + 3 files changed, 36 insertions(+) create mode 100644 java/java-tests/testData/inspection/defUse/ChainedFieldInitializer.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java index 11f16c133b69..d621ce6e1422 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/defUse/DefUseInspectionBase.java @@ -140,6 +140,20 @@ public class DefUseInspectionBase extends AbstractBaseJavaLocalInspectionTool { final List assignments = collectAssignments(field, classInitializer); if (!assignments.isEmpty()) { boolean isDefinitely = HighlightControlFlowUtil.variableDefinitelyAssignedIn(field, classInitializer.getBody()); + if (isDefinitely) { + try { + ControlFlow flow = HighlightControlFlowUtil.getControlFlowNoConstantEvaluate(classInitializer.getBody()); + if (ControlFlowUtil.getReadBeforeWrite(flow) + .stream() + .anyMatch(read -> (isStatic || ExpressionUtil.isEffectivelyUnqualified(read)) && + read.isReferenceTo(field))) { + isDefinitely = false; + } + } + catch (AnalysisCanceledException e) { + // ignore + } + } fieldWrites.add(FieldWrite.createAssignments(isDefinitely, assignments)); } } diff --git a/java/java-tests/testData/inspection/defUse/ChainedFieldInitializer.java b/java/java-tests/testData/inspection/defUse/ChainedFieldInitializer.java new file mode 100644 index 000000000000..abcd58c8572c --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/ChainedFieldInitializer.java @@ -0,0 +1,21 @@ +import java.util.*; + +class Base { + protected Base(Map> aMap) { + } +} + +class SubClass extends Base { + private static Map> aMap = new TreeMap<>(); + static { + aMap = Collections.unmodifiableMap(aMap); + } + public SubClass() { super(aMap); } +} + +class WithStatic { + private static int n = 1; + static { + n = n + 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DefUseTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DefUseTest.java index bae0a2e029a2..5cc2d9327c8d 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DefUseTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DefUseTest.java @@ -59,6 +59,7 @@ public class DefUseTest extends LightCodeInsightFixtureTestCase { public void testNestedTryFinallyInEndlessLoop() { doTest(); } public void testNestedTryFinallyInForLoop() { doTest(); } public void testFieldInitializer() { doTest(); } + public void testChainedFieldInitializer() { doTest(); } public void testFieldIgnoringRedundantInitializer() { DefUseInspection inspection = new DefUseInspection(); inspection.REPORT_REDUNDANT_INITIALIZER = false;