IDEA-51945

This commit is contained in:
Alexey Kudravtsev
2010-02-03 19:00:55 +03:00
parent b8a8286638
commit a1ba40c907
8 changed files with 127 additions and 36 deletions
@@ -48,6 +48,8 @@ public class DfaUtil {
private DfaUtil() {
}
private static final MultiValuesMap<PsiVariable, PsiExpression> TOO_COMPLEX = new MultiValuesMap<PsiVariable, PsiExpression>();
@Nullable("null means DFA analysis has failed (too complex to analyze)")
public static Collection<PsiExpression> 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<MultiValuesMap<PsiVariable, PsiExpression>>(result, codeBlock);
@@ -75,6 +77,7 @@ public class DfaUtil {
context.putUserData(DFA_VARIABLE_INFO_KEY, cachedValue);
}
final MultiValuesMap<PsiVariable, PsiExpression> value = cachedValue.getValue();
if (value == TOO_COMPLEX) return null;
final Collection<PsiExpression> expressions = value == null ? null : value.get(variable);
return expressions == null ? Collections.<PsiExpression>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<? extends PsiElement> 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<? extends PsiElement> variableValues = getCachedVariableValues((PsiVariable)targetElement, (PsiExpression)qualifierExpression);
final Collection<? extends PsiElement> 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<PsiExpression> getVariableAssignmentsInFile(final PsiVariable psiVariable, final boolean literalsOnly) {
final Ref<Boolean> modificationRef = Ref.create(Boolean.FALSE);
final List<PsiExpression> list = ContainerUtil.mapNotNull(
@@ -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<SliceUsage> 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";
}
};
}
}
@@ -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();
}
}
@@ -146,19 +146,15 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> 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;
}
}
@@ -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<SliceUsage> 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";
}
};
}
}
@@ -54,7 +54,6 @@ public class SliceUsage extends UsageInfo2UsageAdapter {
public void processChildren(Processor<SliceUsage> processor) {
final PsiElement element = getElement();
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
//indicator.setText2("<html><body>Searching for usages of "+ StringUtil.trimStart(SliceManager.getElementDescription(element),"<html><body>")+"</body></html>");
indicator.checkCanceled();
final Processor<SliceUsage> uniqueProcessor =
@@ -73,8 +73,12 @@ public class SliceUtil {
}
if (expression instanceof PsiVariable) {
PsiVariable variable = (PsiVariable)expression;
final Set<PsiExpression> expressions = new THashSet<PsiExpression>(DfaUtil.getCachedVariableValues(variable, original));
Collection<PsiExpression> values = DfaUtil.getCachedVariableValues(variable, original);
if (values == null) {
SliceUsage stopUsage = createTooComplexDFAUsage(expression, parent, parentSubstitutor);
return processor.process(stopUsage);
}
final Set<PsiExpression> expressions = new THashSet<PsiExpression>(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<SliceUsage> processor, @NotNull final SliceUsage parent,
@NotNull final PsiSubstitutor parentSubstitutor) {
@@ -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<CachedValue<ConcurrentMap<PsiElement, Object>>> 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<PsiExpression> values =
!useDfa? Collections.<PsiExpression>emptyList() : DfaUtil.getCachedVariableValues(((PsiVariable)resolved), o);
!useDfa? Collections.<PsiExpression>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;
}
}
}
}