diff --git a/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java b/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java index bce9d307d2fd..dcd810b206c7 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java @@ -61,14 +61,11 @@ class SliceUsageCellRenderer extends SliceUsageCellRendererBase { } } - if (javaSliceUsage != null) { - for (int i = 0; i < javaSliceUsage.indexNesting; i++) { - append( - " (Tracking container contents" + - (javaSliceUsage.syntheticField.isEmpty() ? "" : " '" + javaSliceUsage.syntheticField + "'") + - ")", - SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); - } + if (javaSliceUsage != null && javaSliceUsage.indexNesting != 0) { + append( + " (Tracking container '" + getContainerName(javaSliceUsage) + + (javaSliceUsage.syntheticField.isEmpty() ? "" : "." + javaSliceUsage.syntheticField) + "' contents)", + SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); } PsiElement element = sliceUsage.getElement(); @@ -101,5 +98,28 @@ class SliceUsageCellRenderer extends SliceUsageCellRendererBase { } } } + + @NotNull + private static String getContainerName(@NotNull JavaSliceUsage usage) { + String result = ""; + JavaSliceUsage prev = usage; + String name = ""; + while (usage != null) { + if (usage.indexNesting != prev.indexNesting) { + result = name + (result.isEmpty() ? "" : ".") + result; + if (usage.indexNesting == 0) break; + } + PsiElement element = usage.getElement(); + if (element instanceof PsiNamedElement) { + name = ((PsiNamedElement)element).getName(); + } + else if (element instanceof PsiReference) { + name = ((PsiReference)element).getCanonicalText(); + } + prev = usage; + usage = (JavaSliceUsage)usage.getParent(); + } + return result; + } } diff --git a/java/java-impl/src/com/intellij/slicer/SliceUtil.java b/java/java-impl/src/com/intellij/slicer/SliceUtil.java index 1b9ad43f3e40..5500e95542fa 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUtil.java @@ -16,6 +16,7 @@ package com.intellij.slicer; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInspection.dataFlow.DfaPsiUtil; import com.intellij.codeInspection.dataFlow.DfaUtil; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.progress.ProgressManager; @@ -42,10 +43,7 @@ import org.intellij.lang.annotations.Flow; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author cdr @@ -117,11 +115,20 @@ class SliceUtil { SliceUsage stopUsage = createTooComplexDFAUsage(expression, parent); return processor.process(stopUsage); } - final Set expressions = new THashSet<>(values); PsiExpression initializer = variable.getInitializer(); - if (initializer != null && expressions.isEmpty()) expressions.add(initializer); + if (values.isEmpty() && initializer != null) { + values = Collections.singletonList(initializer); + } boolean initializerReported = false; - for (PsiExpression exp : expressions) { + // no need to search and report assignments if we are going to report the variable anyway - it would create duplicate nodes if we did + if (values.isEmpty() && !(variable instanceof PsiParameter) && !needToReportDeclaration) { + values = DfaPsiUtil.getVariableAssignmentsInFile(variable, false, variable.getContainingFile().getLastChild()); + initializerReported = !values.isEmpty(); + } + else if (!values.isEmpty() && !(variable instanceof PsiParameter)) { + needToReportDeclaration = false; // already found all values + } + for (PsiExpression exp : values) { if (!handToProcessor(exp, processor, parent, parentSubstitutor, indexNesting, syntheticField)) return false; if (exp == initializer) initializerReported = true; } diff --git a/java/java-tests/testData/codeInsight/slice/backward/FinalVarAssignedBeforePassingToAnonymous.java b/java/java-tests/testData/codeInsight/slice/backward/FinalVarAssignedBeforePassingToAnonymous.java new file mode 100644 index 000000000000..e9212dd35437 --- /dev/null +++ b/java/java-tests/testData/codeInsight/slice/backward/FinalVarAssignedBeforePassingToAnonymous.java @@ -0,0 +1,17 @@ +import javax.swing.*; + +class Foo { + void foo(String s) { + } + + void bar() { + final String res; + res = "a"; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + foo(res); + } + }); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/slice/backward/LocalVarDeclarationAndAssignment.java b/java/java-tests/testData/codeInsight/slice/backward/LocalVarDeclarationAndAssignment.java new file mode 100644 index 000000000000..caec8e2e7807 --- /dev/null +++ b/java/java-tests/testData/codeInsight/slice/backward/LocalVarDeclarationAndAssignment.java @@ -0,0 +1,11 @@ +class Foo1 { + void foo() { + String s = bar(); + } + + String bar() { + String res; + res = "a"; + return res; + } +} diff --git a/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java b/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java index 44cecdbfd029..485d4ed87f5c 100644 --- a/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java +++ b/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java @@ -81,4 +81,6 @@ public class SliceBackwardTest extends SliceTestCase { public void testListTrackToArray() throws Exception { doTest();} public void testTryCatchFinally() throws Exception { doTest();} + public void testFinalVarAssignedBeforePassingToAnonymous() throws Exception { doTest();} + public void testLocalVarDeclarationAndAssignment() throws Exception { doTest();} }