IDEA-169542 'Analyze Dataflow to Here' misses assignment to variables passed to anonymous classes

This commit is contained in:
Alexey Kudravtsev
2017-03-16 14:57:24 +03:00
parent f0bedf4d71
commit ee62f51f3e
5 changed files with 72 additions and 15 deletions
@@ -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;
}
}
@@ -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<PsiExpression> 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;
}
@@ -0,0 +1,17 @@
import javax.swing.*;
class Foo {
void foo(String <caret>s) {
}
void bar() {
final String <flown11>res;
res = <flown111>"a";
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
foo(<flown1>res);
}
});
}
}
@@ -0,0 +1,11 @@
class Foo1 {
void foo() {
String <caret>s = <flown1>bar();
}
String bar() {
String res;
res = <flown111>"a";
return <flown11>res;
}
}
@@ -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();}
}