From a1ba40c907bd0706a6a322acb27f777b60db1fc6 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 3 Feb 2010 16:45:09 +0300 Subject: [PATCH] IDEA-51945 --- .../codeInspection/dataFlow/DfaUtil.java | 12 +++- .../slicer/SliceDereferenceUsage.java | 30 ++++++++ .../slicer/SliceLeafValueRootNode.java | 15 ---- .../src/com/intellij/slicer/SliceNode.java | 10 +-- .../slicer/SliceTooComplexDFAUsage.java | 69 +++++++++++++++++++ .../src/com/intellij/slicer/SliceUsage.java | 1 - .../src/com/intellij/slicer/SliceUtil.java | 11 ++- ...SubstitutedExpressionEvaluationHelper.java | 15 ++-- 8 files changed, 127 insertions(+), 36 deletions(-) create mode 100644 java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index 36a7e4878e1e..1bcbe7ae9380 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -48,6 +48,8 @@ public class DfaUtil { private DfaUtil() { } + private static final MultiValuesMap TOO_COMPLEX = new MultiValuesMap(); + @Nullable("null means DFA analysis has failed (too complex to analyze)") public static Collection getCachedVariableValues(@Nullable final PsiVariable variable, @Nullable final PsiElement context) { if (variable == null || context == null) return Collections.emptyList(); @@ -66,7 +68,7 @@ public class DfaUtil { result = visitor.myValues; } else { - result = null; + result = TOO_COMPLEX; } } return new Result>(result, codeBlock); @@ -75,6 +77,7 @@ public class DfaUtil { context.putUserData(DFA_VARIABLE_INFO_KEY, cachedValue); } final MultiValuesMap value = cachedValue.getValue(); + if (value == TOO_COMPLEX) return null; final Collection expressions = value == null ? null : value.get(variable); return expressions == null ? Collections.emptyList() : expressions; } @@ -82,7 +85,7 @@ public class DfaUtil { public static enum Nullness { NOT_NULL,NULL,UNKNOWN } - // TRUE->not null, FALSE->null, null->unknown + @NotNull public static Nullness checkNullness(@Nullable final PsiVariable variable, @Nullable final PsiElement context) { if (variable == null || context == null) return Nullness.UNKNOWN; @@ -140,6 +143,7 @@ public class DfaUtil { return codeBlock; } + @Nullable("null means DFA analysis has failed (too complex to analyze)") public static Collection getPossibleInitializationElements(final PsiElement qualifierExpression) { if (qualifierExpression instanceof PsiMethodCallExpression) { return Collections.singletonList(qualifierExpression); @@ -147,7 +151,8 @@ public class DfaUtil { else if (qualifierExpression instanceof PsiReferenceExpression) { final PsiElement targetElement = ((PsiReferenceExpression)qualifierExpression).resolve(); if (targetElement instanceof PsiVariable) { - final Collection variableValues = getCachedVariableValues((PsiVariable)targetElement, (PsiExpression)qualifierExpression); + final Collection variableValues = getCachedVariableValues((PsiVariable)targetElement, qualifierExpression); + if (variableValues == null) return null; if (variableValues.isEmpty() && targetElement instanceof PsiField) { return getVariableAssignmentsInFile((PsiVariable)targetElement, false); } @@ -160,6 +165,7 @@ public class DfaUtil { return Collections.emptyList(); } + @NotNull public static Collection getVariableAssignmentsInFile(final PsiVariable psiVariable, final boolean literalsOnly) { final Ref modificationRef = Ref.create(Boolean.FALSE); final List list = ContainerUtil.mapNotNull( diff --git a/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java b/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java index a53baf82e11c..2fac0dd884f5 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java +++ b/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java @@ -17,9 +17,13 @@ package com.intellij.slicer; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiSubstitutor; +import com.intellij.usages.TextChunk; +import com.intellij.usages.UsagePresentation; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + /** * User: cdr */ @@ -32,4 +36,30 @@ public class SliceDereferenceUsage extends SliceUsage { public void processChildren(Processor processor) { // no children } + + @NotNull + @Override + public UsagePresentation getPresentation() { + final UsagePresentation presentation = super.getPresentation(); + + return new UsagePresentation() { + @NotNull + public TextChunk[] getText() { + return presentation.getText(); + } + + @NotNull + public String getPlainText() { + return presentation.getPlainText(); + } + + public Icon getIcon() { + return presentation.getIcon(); + } + + public String getTooltipText() { + return "Variable dereferenced"; + } + }; + } } diff --git a/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java b/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java index 82b714aeac8d..8f4e245ae4c4 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java @@ -91,19 +91,4 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe renderer.append("Other", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); } } - - @Override - public void navigate(boolean requestFocus) { - getValue().navigate(requestFocus); - } - - @Override - public boolean canNavigate() { - return getValue().canNavigate(); - } - - @Override - public boolean canNavigateToSource() { - return getValue().canNavigateToSource(); - } } diff --git a/java/java-impl/src/com/intellij/slicer/SliceNode.java b/java/java-impl/src/com/intellij/slicer/SliceNode.java index 827b1444dae2..78749ce354ef 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceNode.java @@ -146,19 +146,15 @@ public class SliceNode extends AbstractTreeNode implements Duplicate protected void update(PresentationData presentation) { if (!initialized) { - duplicate = targetEqualUsages.putNodeCheckDupe(this); + if (!(getValue() instanceof SliceTooComplexDFAUsage)) duplicate = targetEqualUsages.putNodeCheckDupe(this); initialized = true; } if (presentation != null) { - presentation.setChanged(presentation.isChanged() || changed); - changed = false; if (duplicate != null) { presentation.setTooltip("Duplicate node"); } - - if (getValue() instanceof SliceDereferenceUsage) { - presentation.setTooltip("Variable dereferenced"); - } + presentation.setChanged(presentation.isChanged() || changed); + changed = false; } } diff --git a/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java b/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java new file mode 100644 index 000000000000..03bb3a167481 --- /dev/null +++ b/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.slicer; + +import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.usages.TextChunk; +import com.intellij.usages.UsagePresentation; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * User: cdr + */ +public class SliceTooComplexDFAUsage extends SliceUsage { + public SliceTooComplexDFAUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) { + super(element, parent, substitutor); + } + + @Override + public void processChildren(Processor processor) { + // no children + } + + @NotNull + @Override + public UsagePresentation getPresentation() { + final UsagePresentation presentation = super.getPresentation(); + return new UsagePresentation() { + @NotNull + public TextChunk[] getText() { + return new TextChunk[]{ + new TextChunk(new TextAttributes(Color.RED, null, null, EffectType.WAVE_UNDERSCORE, Font.PLAIN), getTooltipText()) + }; + } + + @NotNull + public String getPlainText() { + return presentation.getPlainText(); + } + + public Icon getIcon() { + return presentation.getIcon(); + } + + public String getTooltipText() { + return "Too complex to analyze, analysis stoppped here"; + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/slicer/SliceUsage.java b/java/java-impl/src/com/intellij/slicer/SliceUsage.java index e4c6b5374bef..b7965c25e323 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUsage.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUsage.java @@ -54,7 +54,6 @@ public class SliceUsage extends UsageInfo2UsageAdapter { public void processChildren(Processor processor) { final PsiElement element = getElement(); ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - //indicator.setText2("Searching for usages of "+ StringUtil.trimStart(SliceManager.getElementDescription(element),"")+""); indicator.checkCanceled(); final Processor uniqueProcessor = diff --git a/java/java-impl/src/com/intellij/slicer/SliceUtil.java b/java/java-impl/src/com/intellij/slicer/SliceUtil.java index 2185ac0a5d32..fef3a5487f3d 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUtil.java @@ -73,8 +73,12 @@ public class SliceUtil { } if (expression instanceof PsiVariable) { PsiVariable variable = (PsiVariable)expression; - - final Set expressions = new THashSet(DfaUtil.getCachedVariableValues(variable, original)); + Collection values = DfaUtil.getCachedVariableValues(variable, original); + if (values == null) { + SliceUsage stopUsage = createTooComplexDFAUsage(expression, parent, parentSubstitutor); + return processor.process(stopUsage); + } + final Set expressions = new THashSet(values); PsiExpression initializer = variable.getInitializer(); if (initializer != null && expressions.isEmpty()) expressions.add(initializer); for (PsiExpression exp : expressions) { @@ -232,6 +236,9 @@ public class SliceUtil { public static SliceUsage createSliceUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) { return new SliceUsage(simplify(element), parent, substitutor); } + public static SliceUsage createTooComplexDFAUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) { + return new SliceTooComplexDFAUsage(simplify(element), parent, substitutor); + } static boolean processParameterUsages(@NotNull final PsiParameter parameter, @NotNull final Processor processor, @NotNull final SliceUsage parent, @NotNull final PsiSubstitutor parentSubstitutor) { diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java index 51b252465365..c71decb9f1fd 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java @@ -18,9 +18,7 @@ package org.intellij.plugins.intelliLang.util; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.dataFlow.DfaUtil; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; import com.intellij.psi.*; -import com.intellij.psi.util.CachedValue; import com.intellij.util.containers.ConcurrentHashMap; import org.intellij.plugins.intelliLang.Configuration; import org.jetbrains.annotations.Nullable; @@ -37,7 +35,6 @@ import java.util.concurrent.ConcurrentMap; * This is a quite simplified implementation at the moment. */ public class SubstitutedExpressionEvaluationHelper { - private static final Key>> COMPUTED_MAP_KEY = Key.create("COMPUTED_MAP_KEY"); private final PsiConstantEvaluationHelper myHelper; private final Configuration myConfiguration; @@ -78,12 +75,14 @@ public class SubstitutedExpressionEvaluationHelper { if (resolved instanceof PsiVariable) { resolvedType = ((PsiVariable)resolved).getType(); final Collection values = - !useDfa? Collections.emptyList() : DfaUtil.getCachedVariableValues(((PsiVariable)resolved), o); + !useDfa? Collections.emptyList() : DfaUtil.getCachedVariableValues((PsiVariable)resolved, o); // return the first computed value as far as we do not support multiple injection - for (PsiExpression value : values) { - final Object computedValue = auxEvaluator.computeExpression(value, this); - if (computedValue != null) { - return computedValue; + if (values != null) { + for (PsiExpression value : values) { + final Object computedValue = auxEvaluator.computeExpression(value, this); + if (computedValue != null) { + return computedValue; + } } } }