mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merging php-slicing feature branch
This commit is contained in:
+2
-5
@@ -41,10 +41,7 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.slicer.DuplicateMap;
|
||||
import com.intellij.slicer.SliceAnalysisParams;
|
||||
import com.intellij.slicer.SliceRootNode;
|
||||
import com.intellij.slicer.SliceUsage;
|
||||
import com.intellij.slicer.*;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -640,7 +637,7 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool {
|
||||
params.dataFlowToThis = true;
|
||||
params.scope = new AnalysisScope(new LocalSearchScope(scope), manager.getProject());
|
||||
|
||||
SliceRootNode rootNode = new SliceRootNode(manager.getProject(), new DuplicateMap(), SliceUsage.createRootUsage(argument, params));
|
||||
SliceRootNode rootNode = new SliceRootNode(manager.getProject(), new DuplicateMap(), LanguageSlicing.getProvider(argument).createRootUsage(argument, params));
|
||||
|
||||
Collection<? extends AbstractTreeNode> children = rootNode.getChildren().iterator().next().getChildren();
|
||||
for (AbstractTreeNode child : children) {
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ import javax.swing.*;
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
public class SliceDereferenceUsage extends SliceUsage {
|
||||
public SliceDereferenceUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) {
|
||||
public class JavaSliceDereferenceUsage extends JavaSliceUsage {
|
||||
public JavaSliceDereferenceUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) {
|
||||
super(element, parent, substitutor,0,"");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.ide.util.treeView.AbstractTreeStructure;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class JavaSliceProvider implements SliceLanguageSupportProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public SliceUsage createRootUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) {
|
||||
return JavaSliceUsage.createRootUsage(element, params);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement getExpressionAtCaret(PsiElement atCaret, boolean dataFlowToThis) {
|
||||
PsiElement element = PsiTreeUtil.getParentOfType(atCaret, PsiExpression.class, PsiVariable.class);
|
||||
if (dataFlowToThis && element instanceof PsiLiteralExpression) return null;
|
||||
return element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getElementForDescription(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
PsiElement elementToSlice = ((PsiReferenceExpression)element).resolve();
|
||||
if (elementToSlice != null) {
|
||||
return elementToSlice;
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SliceUsageCellRendererBase getRenderer() {
|
||||
return new SliceUsageCellRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAnalyzeLeafValues(AbstractTreeStructure structure, Runnable finalRunnable) {
|
||||
SliceLeafAnalyzer.startAnalyzeValues(structure, finalRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAnalyzeNullness(AbstractTreeStructure structure, Runnable finalRunnable) {
|
||||
SliceNullnessAnalyzer.startAnalyzeNullness(structure, finalRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerExtraPanelActions(DefaultActionGroup actionGroup, SliceTreeBuilder sliceTreeBuilder) {
|
||||
if (sliceTreeBuilder.dataFlowToThis) {
|
||||
actionGroup.add(new GroupByLeavesAction(sliceTreeBuilder));
|
||||
actionGroup.add(new CanItBeNullAction(sliceTreeBuilder));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.psi.PsiElement;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JavaSliceUsage extends SliceUsage {
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
protected final int indexNesting; // 0 means bare expression 'x', 1 means x[?], 2 means x[?][?] etc
|
||||
@NotNull protected final String syntheticField; // "" means no field, otherwise it's a name of fake field of container, e.g. "keys" for Map
|
||||
|
||||
|
||||
public JavaSliceUsage(@NotNull PsiElement element,
|
||||
@NotNull SliceUsage parent,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
int indexNesting,
|
||||
@NotNull String syntheticField) {
|
||||
super(element, parent);
|
||||
mySubstitutor = substitutor;
|
||||
this.syntheticField = syntheticField;
|
||||
this.indexNesting = indexNesting;
|
||||
}
|
||||
|
||||
// root usage
|
||||
private JavaSliceUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) {
|
||||
super(element, params);
|
||||
mySubstitutor = PsiSubstitutor.EMPTY;
|
||||
indexNesting = 0;
|
||||
syntheticField = "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JavaSliceUsage createRootUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) {
|
||||
return new JavaSliceUsage(element, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processUsagesFlownFromThe(PsiElement element, Processor<SliceUsage> uniqueProcessor) {
|
||||
SliceForwardUtil.processUsagesFlownFromThe(element, uniqueProcessor, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processUsagesFlownDownTo(PsiElement element, Processor<SliceUsage> uniqueProcessor) {
|
||||
SliceUtil.processUsagesFlownDownTo(element, uniqueProcessor, this, mySubstitutor, indexNesting,syntheticField);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected SliceUsage copy() {
|
||||
PsiElement element = getUsageInfo().getElement();
|
||||
return getParent() == null ? createRootUsage(element, params) :
|
||||
new JavaSliceUsage(element, getParent(), mySubstitutor, indexNesting, syntheticField);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
return mySubstitutor;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import java.util.Set;
|
||||
* @author cdr
|
||||
*/
|
||||
public class SliceForwardUtil {
|
||||
public static boolean processUsagesFlownFromThe(@NotNull PsiElement element, @NotNull final Processor<SliceUsage> processor, @NotNull final SliceUsage parent) {
|
||||
public static boolean processUsagesFlownFromThe(@NotNull PsiElement element, @NotNull final Processor<SliceUsage> processor, @NotNull final JavaSliceUsage parent) {
|
||||
Pair<PsiElement, PsiSubstitutor> pair = getAssignmentTarget(element, parent);
|
||||
if (pair != null) {
|
||||
PsiElement target = pair.getFirst();
|
||||
@@ -94,7 +94,7 @@ public class SliceForwardUtil {
|
||||
|
||||
private static boolean processAssignedFrom(final PsiElement from,
|
||||
final PsiElement context,
|
||||
final SliceUsage parent,
|
||||
final JavaSliceUsage parent,
|
||||
@NotNull final Processor<SliceUsage> processor) {
|
||||
if (from instanceof PsiLocalVariable) {
|
||||
return searchReferencesAndProcessAssignmentTarget(from, context, parent, processor);
|
||||
@@ -180,7 +180,7 @@ public class SliceForwardUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean searchReferencesAndProcessAssignmentTarget(@NotNull PsiElement element, @Nullable final PsiElement context, final SliceUsage parent,
|
||||
private static boolean searchReferencesAndProcessAssignmentTarget(@NotNull PsiElement element, @Nullable final PsiElement context, final JavaSliceUsage parent,
|
||||
final Processor<SliceUsage> processor) {
|
||||
return ReferencesSearch.search(element).forEach(new Processor<PsiReference>() {
|
||||
@Override
|
||||
@@ -192,7 +192,7 @@ public class SliceForwardUtil {
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean processAssignmentTarget(PsiElement element, final SliceUsage parent, final Processor<SliceUsage> processor) {
|
||||
private static boolean processAssignmentTarget(PsiElement element, final JavaSliceUsage parent, final Processor<SliceUsage> processor) {
|
||||
if (!parent.params.scope.contains(element)) return true;
|
||||
if (element instanceof PsiCompiledElement) element = element.getNavigationElement();
|
||||
Pair<PsiElement, PsiSubstitutor> pair = getAssignmentTarget(element, parent);
|
||||
@@ -201,7 +201,7 @@ public class SliceForwardUtil {
|
||||
return processor.process(usage);
|
||||
}
|
||||
if (parent.params.showInstanceDereferences && isDereferenced(element)) {
|
||||
SliceUsage usage = new SliceDereferenceUsage(element.getParent(), parent, parent.getSubstitutor());
|
||||
SliceUsage usage = new JavaSliceDereferenceUsage(element.getParent(), parent, parent.getSubstitutor());
|
||||
return processor.process(usage);
|
||||
}
|
||||
return true;
|
||||
@@ -214,7 +214,7 @@ public class SliceForwardUtil {
|
||||
return ((PsiReferenceExpression)parent).getQualifierExpression() == element;
|
||||
}
|
||||
|
||||
private static Pair<PsiElement,PsiSubstitutor> getAssignmentTarget(PsiElement element, SliceUsage parentUsage) {
|
||||
private static Pair<PsiElement,PsiSubstitutor> getAssignmentTarget(PsiElement element, JavaSliceUsage parentUsage) {
|
||||
element = complexify(element);
|
||||
PsiElement target = null;
|
||||
PsiSubstitutor substitutor = parentUsage.getSubstitutor();
|
||||
|
||||
@@ -253,7 +253,7 @@ public class SliceLeafAnalyzer {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final SliceUsage sliceUsage = element.getValue();
|
||||
final JavaSliceUsage sliceUsage = (JavaSliceUsage)element.getValue();
|
||||
|
||||
Collection<? extends AbstractTreeNode> children = element.getChildren();
|
||||
if (children.isEmpty()) {
|
||||
|
||||
@@ -44,7 +44,7 @@ public class SliceLeafValueClassNode extends SliceLeafValueRootNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer,
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRendererBase renderer,
|
||||
@NotNull JTree tree,
|
||||
Object value,
|
||||
boolean selected,
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe
|
||||
|
||||
public SliceLeafValueRootNode(@NotNull Project project, PsiElement leafExpression, SliceNode root, List<SliceNode> children,
|
||||
SliceAnalysisParams params) {
|
||||
super(project, SliceUsage.createRootUsage(leafExpression, params), root.targetEqualUsages);
|
||||
super(project, JavaSliceUsage.createRootUsage(leafExpression, params), root.targetEqualUsages);
|
||||
myCachedChildren = children;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer,
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRendererBase renderer,
|
||||
@NotNull JTree tree,
|
||||
Object value,
|
||||
boolean selected,
|
||||
@@ -96,7 +96,7 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe
|
||||
|
||||
private static void appendElementText(@NotNull UsageInfo2UsageAdapter usage,
|
||||
@NotNull final PsiElement element,
|
||||
@NotNull final SliceUsageCellRenderer renderer) {
|
||||
@NotNull final SliceUsageCellRendererBase renderer) {
|
||||
PsiFile file = element.getContainingFile();
|
||||
List<TextChunk> result = new ArrayList<TextChunk>();
|
||||
ChunkExtractor.getExtractor(element.getContainingFile())
|
||||
|
||||
@@ -15,58 +15,30 @@
|
||||
*/
|
||||
package com.intellij.slicer;
|
||||
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.ColoredTreeCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.usageView.UsageTreeColors;
|
||||
import com.intellij.usageView.UsageTreeColorsScheme;
|
||||
import com.intellij.usages.TextChunk;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public class SliceUsageCellRenderer extends ColoredTreeCellRenderer {
|
||||
private static final EditorColorsScheme ourColorsScheme = UsageTreeColorsScheme.getInstance().getScheme();
|
||||
public static final SimpleTextAttributes ourInvalidAttributes = SimpleTextAttributes.fromTextAttributes(ourColorsScheme.getAttributes(UsageTreeColors.INVALID_PREFIX));
|
||||
|
||||
public SliceUsageCellRenderer() {
|
||||
setOpaque(false);
|
||||
}
|
||||
public class SliceUsageCellRenderer extends SliceUsageCellRendererBase {
|
||||
|
||||
@Override
|
||||
public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
assert value instanceof DefaultMutableTreeNode;
|
||||
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
|
||||
Object userObject = treeNode.getUserObject();
|
||||
if (userObject == null) return;
|
||||
if (userObject instanceof MyColoredTreeCellRenderer) {
|
||||
MyColoredTreeCellRenderer node = (MyColoredTreeCellRenderer)userObject;
|
||||
node.customizeCellRenderer(this, tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
if (node instanceof SliceNode) {
|
||||
setToolTipText(((SliceNode)node).getPresentation().getTooltip());
|
||||
}
|
||||
}
|
||||
else {
|
||||
append(userObject.toString(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
|
||||
public void customizeCellRendererFor(@NotNull SliceUsage sliceUsage) {
|
||||
boolean isForcedLeaf = sliceUsage instanceof SliceDereferenceUsage;
|
||||
boolean isForcedLeaf = sliceUsage instanceof JavaSliceDereferenceUsage;
|
||||
JavaSliceUsage javaSliceUsage = ((JavaSliceUsage)sliceUsage);
|
||||
|
||||
TextChunk[] text = sliceUsage.getText();
|
||||
final List<TextRange> usageRanges = new SmartList<TextRange>();
|
||||
@@ -77,7 +49,7 @@ public class SliceUsageCellRenderer extends ColoredTreeCellRenderer {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
boolean isInsideContainer = sliceUsage.indexNesting != 0;
|
||||
boolean isInsideContainer = javaSliceUsage.indexNesting != 0;
|
||||
for (TextChunk textChunk : text) {
|
||||
SimpleTextAttributes attributes = textChunk.getSimpleAttributesIgnoreBackground();
|
||||
if (isForcedLeaf) {
|
||||
@@ -93,8 +65,8 @@ public class SliceUsageCellRenderer extends ColoredTreeCellRenderer {
|
||||
append(textChunk.getText(), attributes);
|
||||
}
|
||||
|
||||
for (int i=0; i<sliceUsage.indexNesting;i++) {
|
||||
append(" (Tracking container contents"+(sliceUsage.syntheticField.isEmpty() ? "" : " '"+sliceUsage.syntheticField+"'")+")",SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
for (int i=0; i<javaSliceUsage.indexNesting;i++) {
|
||||
append(" (Tracking container contents"+(javaSliceUsage.syntheticField.isEmpty() ? "" : " '"+javaSliceUsage.syntheticField+"'")+")",SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
}
|
||||
|
||||
PsiElement element = sliceUsage.getElement();
|
||||
|
||||
@@ -52,7 +52,7 @@ import java.util.Set;
|
||||
class SliceUtil {
|
||||
static boolean processUsagesFlownDownTo(@NotNull PsiElement expression,
|
||||
@NotNull Processor<SliceUsage> processor,
|
||||
@NotNull SliceUsage parent,
|
||||
@NotNull JavaSliceUsage parent,
|
||||
@NotNull PsiSubstitutor parentSubstitutor,
|
||||
int indexNesting,
|
||||
@NotNull String syntheticField) {
|
||||
@@ -235,7 +235,7 @@ class SliceUtil {
|
||||
|
||||
private static boolean processMethodReturnValue(@NotNull final PsiMethodCallExpression methodCallExpr,
|
||||
@NotNull final Processor<SliceUsage> processor,
|
||||
@NotNull final SliceUsage parent,
|
||||
@NotNull final JavaSliceUsage parent,
|
||||
@NotNull final PsiSubstitutor parentSubstitutor) {
|
||||
final JavaResolveResult resolved = methodCallExpr.resolveMethodGenerics();
|
||||
PsiElement r = resolved.getElement();
|
||||
@@ -293,7 +293,7 @@ class SliceUtil {
|
||||
}
|
||||
|
||||
private static boolean processFieldUsages(@NotNull final PsiField field,
|
||||
@NotNull final SliceUsage parent,
|
||||
@NotNull final JavaSliceUsage parent,
|
||||
@NotNull final PsiSubstitutor parentSubstitutor,
|
||||
@NotNull final Processor<SliceUsage> processor) {
|
||||
if (field.hasInitializer()) {
|
||||
@@ -342,14 +342,14 @@ class SliceUtil {
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
int indexNesting,
|
||||
@NotNull String syntheticField) {
|
||||
return new SliceUsage(simplify(element), parent, substitutor,indexNesting, syntheticField);
|
||||
return new JavaSliceUsage(simplify(element), parent, substitutor,indexNesting, syntheticField);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static SliceUsage createTooComplexDFAUsage(@NotNull PsiElement element,
|
||||
@NotNull SliceUsage parent,
|
||||
@NotNull PsiSubstitutor substitutor) {
|
||||
return new SliceTooComplexDFAUsage(simplify(element), parent, substitutor);
|
||||
return new SliceTooComplexDFAUsage(simplify(element), parent);
|
||||
}
|
||||
|
||||
private static boolean processParameterUsages(@NotNull final PsiParameter parameter,
|
||||
|
||||
@@ -121,7 +121,7 @@ public class UsageContextDataflowToPanel extends UsageContextPanelBase {
|
||||
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND);
|
||||
SliceAnalysisParams params = createParams(element, dataFlowToThis);
|
||||
|
||||
SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), SliceUsage.createRootUsage(element, params));
|
||||
SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), JavaSliceUsage.createRootUsage(element, params));
|
||||
|
||||
return new SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) {
|
||||
@Override
|
||||
|
||||
@@ -47,5 +47,6 @@
|
||||
<orderEntry type="module" module-name="util-tests" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="Mocks" level="project" />
|
||||
<orderEntry type="module" module-name="jetgroovy" scope="TEST" />
|
||||
<orderEntry type="module" module-name="lang-tests" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -43,113 +43,19 @@ public class SliceBackwardTest extends SliceTestCase {
|
||||
|
||||
private void doTest() throws Exception {
|
||||
configureByFile("/codeInsight/slice/backward/"+getTestName(false)+".java");
|
||||
Map<String, RangeMarker> sliceUsageName2Offset = extractSliceOffsetsFromDocument(getEditor().getDocument());
|
||||
Map<String, RangeMarker> sliceUsageName2Offset = SliceTestUtil.extractSliceOffsetsFromDocument(getEditor().getDocument());
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
PsiElement element = new SliceHandler(true).getExpressionAtCaret(getEditor(), getFile());
|
||||
assertNotNull(element);
|
||||
calcRealOffsets(element, sliceUsageName2Offset, myFlownOffsets);
|
||||
SliceTestUtil.calcRealOffsets(element, sliceUsageName2Offset, myFlownOffsets);
|
||||
Collection<HighlightInfo> errors = highlightErrors();
|
||||
assertEmpty(errors);
|
||||
SliceAnalysisParams params = new SliceAnalysisParams();
|
||||
params.scope = new AnalysisScope(getProject());
|
||||
params.dataFlowToThis = true;
|
||||
|
||||
SliceUsage usage = SliceUsage.createRootUsage(element, params);
|
||||
checkUsages(usage, myFlownOffsets);
|
||||
}
|
||||
|
||||
static void checkUsages(final SliceUsage usage, final TIntObjectHashMap<IntArrayList> flownOffsets) {
|
||||
final List<SliceUsage> children = new ArrayList<SliceUsage>();
|
||||
boolean b = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
usage.processChildren(new CommonProcessors.CollectProcessor<SliceUsage>(children));
|
||||
}
|
||||
}, "Expanding", true, usage.getElement().getProject());
|
||||
assertTrue(b);
|
||||
int startOffset = usage.getElement().getTextOffset();
|
||||
IntArrayList list = flownOffsets.get(startOffset);
|
||||
int[] offsets = list == null ? new int[0] : list.toArray();
|
||||
Arrays.sort(offsets);
|
||||
|
||||
int size = offsets.length;
|
||||
assertEquals(message(startOffset, usage), size, children.size());
|
||||
Collections.sort(children, new Comparator<SliceUsage>() {
|
||||
@Override
|
||||
public int compare(SliceUsage o1, SliceUsage o2) {
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
SliceUsage child = children.get(i);
|
||||
int offset = offsets[i];
|
||||
assertEquals(message(offset, child), offset, child.getUsageInfo().getElement().getTextOffset());
|
||||
|
||||
checkUsages(child, flownOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
private static String message(int startOffset, SliceUsage usage) {
|
||||
PsiFile file = usage.getElement().getContainingFile();
|
||||
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
Editor editor = FileEditorManager.getInstance(file.getProject()).getSelectedTextEditor();
|
||||
LogicalPosition position = editor.offsetToLogicalPosition(startOffset);
|
||||
return position + ": '" + StringUtil.first(file.getText().substring(startOffset), 100, true) + "'";
|
||||
}
|
||||
|
||||
static void calcRealOffsets(PsiElement startElement, Map<String, RangeMarker> sliceUsageName2Offset,
|
||||
final TIntObjectHashMap<IntArrayList> flownOffsets) {
|
||||
fill(sliceUsageName2Offset, "", startElement.getTextOffset(), flownOffsets);
|
||||
}
|
||||
|
||||
static Map<String, RangeMarker> extractSliceOffsetsFromDocument(final Document document) {
|
||||
Map<String, RangeMarker> sliceUsageName2Offset = new THashMap<String, RangeMarker>();
|
||||
|
||||
extract(document, sliceUsageName2Offset, "");
|
||||
int index = document.getText().indexOf("<flown");
|
||||
if(index!=-1) {
|
||||
fail(document.getText().substring(index, Math.min(document.getText().length(), index+50)));
|
||||
}
|
||||
assertTrue(!sliceUsageName2Offset.isEmpty());
|
||||
return sliceUsageName2Offset;
|
||||
}
|
||||
|
||||
private static void fill(Map<String, RangeMarker> sliceUsageName2Offset, String name, int offset,
|
||||
final TIntObjectHashMap<IntArrayList> flownOffsets) {
|
||||
for (int i=1;i<9;i++) {
|
||||
String newName = name + i;
|
||||
RangeMarker marker = sliceUsageName2Offset.get(newName);
|
||||
if (marker == null) break;
|
||||
IntArrayList offsets = flownOffsets.get(offset);
|
||||
if (offsets == null) {
|
||||
offsets = new IntArrayList();
|
||||
flownOffsets.put(offset, offsets);
|
||||
}
|
||||
int newStartOffset = marker.getStartOffset();
|
||||
offsets.add(newStartOffset);
|
||||
fill(sliceUsageName2Offset, newName, newStartOffset, flownOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
private static void extract(final Document document, final Map<String, RangeMarker> sliceUsageName2Offset, final String name) {
|
||||
WriteCommandAction.runWriteCommandAction(null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 1; i < 9; i++) {
|
||||
String newName = name + i;
|
||||
String s = "<flown" + newName + ">";
|
||||
if (!document.getText().contains(s)) break;
|
||||
int off = document.getText().indexOf(s);
|
||||
|
||||
document.deleteString(off, off + s.length());
|
||||
RangeMarker prev = sliceUsageName2Offset.put(newName, document.createRangeMarker(off, off));
|
||||
assertNull(prev);
|
||||
|
||||
extract(document, sliceUsageName2Offset, newName);
|
||||
}
|
||||
}
|
||||
});
|
||||
SliceUsage usage = LanguageSlicing.getProvider(element).createRootUsage(element, params);
|
||||
SliceTestUtil.checkUsages(usage, myFlownOffsets);
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception { doTest();}
|
||||
|
||||
@@ -35,18 +35,18 @@ public class SliceForwardTest extends DaemonAnalyzerTestCase {
|
||||
|
||||
private void dotest() throws Exception {
|
||||
configureByFile("/codeInsight/slice/forward/"+getTestName(false)+".java");
|
||||
Map<String, RangeMarker> sliceUsageName2Offset = SliceBackwardTest.extractSliceOffsetsFromDocument(getEditor().getDocument());
|
||||
Map<String, RangeMarker> sliceUsageName2Offset = SliceTestUtil.extractSliceOffsetsFromDocument(getEditor().getDocument());
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
PsiElement element = new SliceForwardHandler().getExpressionAtCaret(getEditor(), getFile());
|
||||
assertNotNull(element);
|
||||
SliceBackwardTest.calcRealOffsets(element, sliceUsageName2Offset, myFlownOffsets);
|
||||
SliceTestUtil.calcRealOffsets(element, sliceUsageName2Offset, myFlownOffsets);
|
||||
Collection<HighlightInfo> errors = highlightErrors();
|
||||
assertEmpty(errors);
|
||||
SliceAnalysisParams params = new SliceAnalysisParams();
|
||||
params.scope = new AnalysisScope(getProject());
|
||||
params.dataFlowToThis = false;
|
||||
SliceUsage usage = SliceUsage.createRootUsage(element, params);
|
||||
SliceBackwardTest.checkUsages(usage, myFlownOffsets);
|
||||
SliceUsage usage = LanguageSlicing.getProvider(element).createRootUsage(element, params);
|
||||
SliceTestUtil.checkUsages(usage, myFlownOffsets);
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception { dotest();}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class SliceTreeTest extends SliceTestCase {
|
||||
params.scope = new AnalysisScope(getProject());
|
||||
params.dataFlowToThis = true;
|
||||
|
||||
SliceUsage usage = SliceUsage.createRootUsage(element, params);
|
||||
SliceUsage usage = LanguageSlicing.getProvider(element).createRootUsage(element, params);
|
||||
|
||||
|
||||
ToolWindowHeadlessManagerImpl.MockToolWindow toolWindow = new ToolWindowHeadlessManagerImpl.MockToolWindow(myProject);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.lang.LanguageExtension;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LanguageSlicing extends LanguageExtension<SliceLanguageSupportProvider> {
|
||||
public static final LanguageSlicing INSTANCE = new LanguageSlicing();
|
||||
|
||||
private LanguageSlicing() {
|
||||
super("com.intellij.lang.sliceProvider");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SliceLanguageSupportProvider getProvider(@NotNull PsiElement element){
|
||||
return INSTANCE.forLanguage(element.getLanguage());
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -23,7 +23,7 @@ import javax.swing.*;
|
||||
* @author cdr
|
||||
*/
|
||||
public interface MyColoredTreeCellRenderer {
|
||||
void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer,
|
||||
void customizeCellRenderer(@NotNull SliceUsageCellRendererBase renderer,
|
||||
@NotNull JTree tree,
|
||||
Object value,
|
||||
boolean selected,
|
||||
+5
-3
@@ -66,9 +66,11 @@ public class SliceHandler implements CodeInsightActionHandler {
|
||||
}
|
||||
PsiElement atCaret = file.findElementAt(offset);
|
||||
|
||||
PsiElement element = PsiTreeUtil.getParentOfType(atCaret, PsiExpression.class, PsiVariable.class);
|
||||
if (myDataFlowToThis && element instanceof PsiLiteralExpression) return null;
|
||||
return element;
|
||||
SliceLanguageSupportProvider provider = LanguageSlicing.getProvider(file);
|
||||
if(provider == null){
|
||||
return null;
|
||||
}
|
||||
return provider.getExpressionAtCaret(atCaret, myDataFlowToThis);
|
||||
}
|
||||
|
||||
public SliceAnalysisParams askForParams(PsiElement element, boolean dataFlowToThis, SliceManager.StoredSettingsBean storedSettingsBean, String dialogTitle) {
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.ide.util.treeView.AbstractTreeStructure;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface SliceLanguageSupportProvider {
|
||||
|
||||
@NotNull
|
||||
SliceUsage createRootUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) ;
|
||||
|
||||
@Nullable
|
||||
PsiElement getExpressionAtCaret(PsiElement atCaret, boolean dataFlowToThis);
|
||||
|
||||
@NotNull
|
||||
PsiElement getElementForDescription(@NotNull PsiElement element);
|
||||
|
||||
@NotNull
|
||||
SliceUsageCellRendererBase getRenderer();
|
||||
|
||||
void startAnalyzeLeafValues(AbstractTreeStructure structure, Runnable finalRunnable);
|
||||
|
||||
void startAnalyzeNullness(AbstractTreeStructure structure, Runnable finalRunnable);
|
||||
|
||||
void registerExtraPanelActions(DefaultActionGroup group, SliceTreeBuilder builder);
|
||||
}
|
||||
+7
-5
@@ -125,7 +125,8 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store
|
||||
SliceAnalysisParams params = handler.askForParams(element, dataFlowToThis, myStoredSettings, dialogTitle);
|
||||
if (params == null) return;
|
||||
|
||||
SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), SliceUsage.createRootUsage(element, params));
|
||||
SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(),
|
||||
LanguageSlicing.getProvider(element).createRootUsage(element, params));
|
||||
|
||||
createToolWindow(dataFlowToThis, rootNode, false, getElementDescription(null, element, null));
|
||||
}
|
||||
@@ -171,10 +172,11 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store
|
||||
}
|
||||
|
||||
public static String getElementDescription(String prefix, PsiElement element, String suffix) {
|
||||
PsiElement elementToSlice = element;
|
||||
if (element instanceof PsiReferenceExpression) elementToSlice = ((PsiReferenceExpression)element).resolve();
|
||||
if (elementToSlice == null) elementToSlice = element;
|
||||
String desc = ElementDescriptionUtil.getElementDescription(elementToSlice, RefactoringDescriptionLocation.WITHOUT_PARENT);
|
||||
SliceLanguageSupportProvider provider = LanguageSlicing.getProvider(element);
|
||||
if(provider != null){
|
||||
element = provider.getElementForDescription(element);
|
||||
}
|
||||
String desc = ElementDescriptionUtil.getElementDescription(element, RefactoringDescriptionLocation.WITHOUT_PARENT);
|
||||
return "<html><head>" + UIUtil.getCssFontDeclaration(BaseLabel.getLabelFont()) + "</head><body>" +
|
||||
(prefix == null ? "" : prefix) + StringUtil.first(desc, 100, true)+(suffix == null ? "" : suffix) +
|
||||
"</body></html>";
|
||||
+22
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -23,11 +23,13 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.ui.DuplicateNodeRenderer;
|
||||
import com.intellij.usageView.UsageViewBundle;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -207,7 +209,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer, @NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRendererBase renderer, @NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
renderer.setIcon(getPresentation().getIcon(expanded));
|
||||
if (isValid()) {
|
||||
SliceUsage sliceUsage = getValue();
|
||||
@@ -215,7 +217,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate
|
||||
renderer.setToolTipText(sliceUsage.getPresentation().getTooltipText());
|
||||
}
|
||||
else {
|
||||
renderer.append(UsageViewBundle.message("node.invalid") + " ", SliceUsageCellRenderer.ourInvalidAttributes);
|
||||
renderer.append(UsageViewBundle.message("node.invalid") + " ", SliceUsageCellRendererBase.ourInvalidAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +225,23 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SliceLanguageSupportProvider getProvider(){
|
||||
AbstractTreeNode<SliceUsage> element = getElement();
|
||||
if(element == null){
|
||||
return null;
|
||||
}
|
||||
SliceUsage usage = element.getValue();
|
||||
if(usage == null){
|
||||
return null;
|
||||
}
|
||||
PsiElement psiElement = usage.getElement();
|
||||
if(psiElement == null){
|
||||
return null;
|
||||
}
|
||||
return LanguageSlicing.getProvider(psiElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
|
||||
+5
-5
@@ -32,6 +32,7 @@ import com.intellij.openapi.wm.ToolWindowAnchor;
|
||||
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
|
||||
import com.intellij.openapi.wm.ex.ToolWindowManagerListener;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
@@ -85,6 +86,7 @@ public abstract class SlicePanel extends JPanel implements TypeSafeDataProvider,
|
||||
private final Project myProject;
|
||||
private boolean isDisposed;
|
||||
private final ToolWindow myToolWindow;
|
||||
private final SliceLanguageSupportProvider myProvider;
|
||||
|
||||
public SlicePanel(@NotNull final Project project,
|
||||
boolean dataFlowToThis,
|
||||
@@ -92,6 +94,7 @@ public abstract class SlicePanel extends JPanel implements TypeSafeDataProvider,
|
||||
boolean splitByLeafExpressions,
|
||||
@NotNull final ToolWindow toolWindow) {
|
||||
super(new BorderLayout());
|
||||
myProvider = rootNode.getProvider();
|
||||
myToolWindow = toolWindow;
|
||||
final ToolWindowManagerListener listener = new ToolWindowManagerListener() {
|
||||
ToolWindowAnchor myAnchor = toolWindow.getAnchor();
|
||||
@@ -194,7 +197,7 @@ public abstract class SlicePanel extends JPanel implements TypeSafeDataProvider,
|
||||
tree.setOpaque(false);
|
||||
|
||||
tree.setToggleClickCount(-1);
|
||||
SliceUsageCellRenderer renderer = new SliceUsageCellRenderer();
|
||||
SliceUsageCellRendererBase renderer = myProvider.getRenderer();
|
||||
renderer.setOpaque(false);
|
||||
tree.setCellRenderer(renderer);
|
||||
UIUtil.setLineStyleAngled(tree);
|
||||
@@ -354,10 +357,7 @@ public abstract class SlicePanel extends JPanel implements TypeSafeDataProvider,
|
||||
});
|
||||
}
|
||||
|
||||
if (myBuilder.dataFlowToThis) {
|
||||
actionGroup.add(new GroupByLeavesAction(myBuilder));
|
||||
actionGroup.add(new CanItBeNullAction(myBuilder));
|
||||
}
|
||||
myProvider.registerExtraPanelActions(actionGroup, myBuilder);
|
||||
|
||||
//actionGroup.add(new ContextHelpAction(HELP_ID));
|
||||
|
||||
+5
-2
@@ -33,7 +33,10 @@ public class SliceRootNode extends SliceNode {
|
||||
private final SliceUsage myRootUsage;
|
||||
|
||||
public SliceRootNode(@NotNull Project project, @NotNull DuplicateMap targetEqualUsages, final SliceUsage rootUsage) {
|
||||
super(project, SliceUsage.createRootUsage(rootUsage.getElement().getContainingFile(), rootUsage.params), targetEqualUsages);
|
||||
super(project,
|
||||
LanguageSlicing.getProvider(rootUsage.getElement().getContainingFile()).
|
||||
createRootUsage(rootUsage.getElement().getContainingFile(), rootUsage.params),
|
||||
targetEqualUsages);
|
||||
myRootUsage = rootUsage;
|
||||
}
|
||||
|
||||
@@ -82,7 +85,7 @@ public class SliceRootNode extends SliceNode {
|
||||
|
||||
|
||||
@Override
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer,
|
||||
public void customizeCellRenderer(@NotNull SliceUsageCellRendererBase renderer,
|
||||
@NotNull JTree tree,
|
||||
Object value,
|
||||
boolean selected,
|
||||
+19
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -18,7 +18,6 @@ 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.ui.JBColor;
|
||||
import com.intellij.usages.TextChunk;
|
||||
import com.intellij.usages.UsagePresentation;
|
||||
@@ -32,8 +31,8 @@ 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,0,"");
|
||||
public SliceTooComplexDFAUsage(@NotNull PsiElement element, @NotNull SliceUsage parent) {
|
||||
super(element, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,6 +40,22 @@ public class SliceTooComplexDFAUsage extends SliceUsage {
|
||||
// no children
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processUsagesFlownFromThe(PsiElement element, Processor<SliceUsage> uniqueProcessor) {
|
||||
// no children
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processUsagesFlownDownTo(PsiElement element, Processor<SliceUsage> uniqueProcessor) {
|
||||
// no children
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected SliceUsage copy() {
|
||||
return new SliceTooComplexDFAUsage(getUsageInfo().getElement(), getParent());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public UsagePresentation getPresentation() {
|
||||
+18
-2
@@ -85,8 +85,12 @@ public class SliceTreeBuilder extends AbstractTreeBuilder {
|
||||
}
|
||||
|
||||
public void switchToGroupedByLeavesNodes() {
|
||||
SliceLanguageSupportProvider provider = getRootSliceNode().getProvider();
|
||||
if(provider == null){
|
||||
return;
|
||||
}
|
||||
analysisInProgress = true;
|
||||
SliceLeafAnalyzer.startAnalyzeValues(getTreeStructure(), new Runnable(){
|
||||
provider.startAnalyzeLeafValues(getTreeStructure(), new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
analysisInProgress = false;
|
||||
@@ -96,8 +100,20 @@ public class SliceTreeBuilder extends AbstractTreeBuilder {
|
||||
|
||||
|
||||
public void switchToLeafNulls() {
|
||||
SliceLanguageSupportProvider provider = getRootSliceNode().getProvider();
|
||||
if(provider == null){
|
||||
return;
|
||||
}
|
||||
analysisInProgress = true;
|
||||
SliceNullnessAnalyzer.startAnalyzeNullness(getTreeStructure(), new Runnable(){
|
||||
provider.startAnalyzeLeafValues(getTreeStructure(), new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
analysisInProgress = false;
|
||||
}
|
||||
});
|
||||
|
||||
analysisInProgress = true;
|
||||
provider.startAnalyzeNullness(getTreeStructure(), new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
analysisInProgress = false;
|
||||
+11
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -21,7 +21,6 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usages.UsageInfo2UsageAdapter;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
@@ -32,40 +31,23 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public class SliceUsage extends UsageInfo2UsageAdapter {
|
||||
public abstract class SliceUsage extends UsageInfo2UsageAdapter {
|
||||
private final SliceUsage myParent;
|
||||
public final SliceAnalysisParams params;
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
protected final int indexNesting; // 0 means bare expression 'x', 1 means x[?], 2 means x[?][?] etc
|
||||
@NotNull protected final String syntheticField; // "" means no field, otherwise it's a name of fake field of container, e.g. "keys" for Map
|
||||
|
||||
public SliceUsage(@NotNull PsiElement element,
|
||||
@NotNull SliceUsage parent,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
int indexNesting,
|
||||
@NotNull String syntheticField) {
|
||||
@NotNull SliceUsage parent) {
|
||||
super(new UsageInfo(element));
|
||||
myParent = parent;
|
||||
mySubstitutor = substitutor;
|
||||
this.syntheticField = syntheticField;
|
||||
params = parent.params;
|
||||
assert params != null;
|
||||
this.indexNesting = indexNesting;
|
||||
}
|
||||
|
||||
// root usage
|
||||
private SliceUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) {
|
||||
protected SliceUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) {
|
||||
super(new UsageInfo(element));
|
||||
myParent = null;
|
||||
this.params = params;
|
||||
mySubstitutor = PsiSubstitutor.EMPTY;
|
||||
indexNesting = 0;
|
||||
syntheticField = "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SliceUsage createRootUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) {
|
||||
return new SliceUsage(element, params);
|
||||
}
|
||||
|
||||
public void processChildren(@NotNull Processor<SliceUsage> processor) {
|
||||
@@ -95,15 +77,19 @@ public class SliceUsage extends UsageInfo2UsageAdapter {
|
||||
@Override
|
||||
public void run() {
|
||||
if (params.dataFlowToThis) {
|
||||
SliceUtil.processUsagesFlownDownTo(element, uniqueProcessor, SliceUsage.this, mySubstitutor, indexNesting,syntheticField);
|
||||
processUsagesFlownDownTo(element, uniqueProcessor);
|
||||
}
|
||||
else {
|
||||
SliceForwardUtil.processUsagesFlownFromThe(element, uniqueProcessor, SliceUsage.this);
|
||||
processUsagesFlownFromThe(element, uniqueProcessor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void processUsagesFlownFromThe(PsiElement element, Processor<SliceUsage> uniqueProcessor);
|
||||
|
||||
protected abstract void processUsagesFlownDownTo(PsiElement element, Processor<SliceUsage> uniqueProcessor);
|
||||
|
||||
public SliceUsage getParent() {
|
||||
return myParent;
|
||||
}
|
||||
@@ -114,13 +100,5 @@ public class SliceUsage extends UsageInfo2UsageAdapter {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
SliceUsage copy() {
|
||||
PsiElement element = getUsageInfo().getElement();
|
||||
return getParent() == null ? createRootUsage(element, params) : new SliceUsage(element, getParent(),mySubstitutor,indexNesting,syntheticField);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
return mySubstitutor;
|
||||
}
|
||||
protected abstract SliceUsage copy();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.colors.EditorColorsScheme;
|
||||
import com.intellij.ui.ColoredTreeCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.usageView.UsageTreeColors;
|
||||
import com.intellij.usageView.UsageTreeColorsScheme;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public abstract class SliceUsageCellRendererBase extends ColoredTreeCellRenderer {
|
||||
private static final EditorColorsScheme ourColorsScheme = UsageTreeColorsScheme.getInstance().getScheme();
|
||||
public static final SimpleTextAttributes ourInvalidAttributes = SimpleTextAttributes.fromTextAttributes(ourColorsScheme.getAttributes(UsageTreeColors.INVALID_PREFIX));
|
||||
|
||||
public SliceUsageCellRendererBase() {
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
assert value instanceof DefaultMutableTreeNode;
|
||||
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
|
||||
Object userObject = treeNode.getUserObject();
|
||||
if (userObject == null) return;
|
||||
if (userObject instanceof MyColoredTreeCellRenderer) {
|
||||
MyColoredTreeCellRenderer node = (MyColoredTreeCellRenderer)userObject;
|
||||
node.customizeCellRenderer(this, tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
if (node instanceof SliceNode) {
|
||||
setToolTipText(((SliceNode)node).getPresentation().getTooltip());
|
||||
}
|
||||
}
|
||||
else {
|
||||
append(userObject.toString(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void customizeCellRendererFor(@NotNull SliceUsage sliceUsage);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static junit.framework.TestCase.*;
|
||||
|
||||
public class SliceTestUtil {
|
||||
|
||||
private SliceTestUtil() {
|
||||
}
|
||||
|
||||
public static void calcRealOffsets(PsiElement startElement, Map<String, RangeMarker> sliceUsageName2Offset,
|
||||
final TIntObjectHashMap<IntArrayList> flownOffsets) {
|
||||
fill(sliceUsageName2Offset, "", startElement.getTextOffset(), flownOffsets);
|
||||
}
|
||||
|
||||
public static Map<String, RangeMarker> extractSliceOffsetsFromDocument(final Document document) {
|
||||
Map<String, RangeMarker> sliceUsageName2Offset = new THashMap<String, RangeMarker>();
|
||||
|
||||
extract(document, sliceUsageName2Offset, "");
|
||||
int index = document.getText().indexOf("<flown");
|
||||
if(index!=-1) {
|
||||
fail(document.getText().substring(index, Math.min(document.getText().length(), index+50)));
|
||||
}
|
||||
assertTrue(!sliceUsageName2Offset.isEmpty());
|
||||
return sliceUsageName2Offset;
|
||||
}
|
||||
|
||||
private static void fill(Map<String, RangeMarker> sliceUsageName2Offset, String name, int offset,
|
||||
final TIntObjectHashMap<IntArrayList> flownOffsets) {
|
||||
for (int i=1;i<9;i++) {
|
||||
String newName = name + i;
|
||||
RangeMarker marker = sliceUsageName2Offset.get(newName);
|
||||
if (marker == null) break;
|
||||
IntArrayList offsets = flownOffsets.get(offset);
|
||||
if (offsets == null) {
|
||||
offsets = new IntArrayList();
|
||||
flownOffsets.put(offset, offsets);
|
||||
}
|
||||
int newStartOffset = marker.getStartOffset();
|
||||
offsets.add(newStartOffset);
|
||||
fill(sliceUsageName2Offset, newName, newStartOffset, flownOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
private static void extract(final Document document, final Map<String, RangeMarker> sliceUsageName2Offset, final String name) {
|
||||
WriteCommandAction.runWriteCommandAction(null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 1; i < 9; i++) {
|
||||
String newName = name + i;
|
||||
String s = "<flown" + newName + ">";
|
||||
if (!document.getText().contains(s)) break;
|
||||
int off = document.getText().indexOf(s);
|
||||
|
||||
document.deleteString(off, off + s.length());
|
||||
RangeMarker prev = sliceUsageName2Offset.put(newName, document.createRangeMarker(off, off));
|
||||
assertNull(prev);
|
||||
|
||||
extract(document, sliceUsageName2Offset, newName);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void checkUsages(final SliceUsage usage, final TIntObjectHashMap<IntArrayList> flownOffsets) {
|
||||
final List<SliceUsage> children = new ArrayList<SliceUsage>();
|
||||
boolean b = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
usage.processChildren(new CommonProcessors.CollectProcessor<SliceUsage>(children));
|
||||
}
|
||||
}, "Expanding", true, usage.getElement().getProject());
|
||||
assertTrue(b);
|
||||
int startOffset = usage.getElement().getTextOffset();
|
||||
IntArrayList list = flownOffsets.get(startOffset);
|
||||
int[] offsets = list == null ? new int[0] : list.toArray();
|
||||
Arrays.sort(offsets);
|
||||
|
||||
int size = offsets.length;
|
||||
assertEquals(message(startOffset, usage), size, children.size());
|
||||
Collections.sort(children, new Comparator<SliceUsage>() {
|
||||
@Override
|
||||
public int compare(SliceUsage o1, SliceUsage o2) {
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
SliceUsage child = children.get(i);
|
||||
int offset = offsets[i];
|
||||
assertEquals(message(offset, child), offset, child.getUsageInfo().getElement().getTextOffset());
|
||||
|
||||
checkUsages(child, flownOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
private static String message(int startOffset, SliceUsage usage) {
|
||||
PsiFile file = usage.getElement().getContainingFile();
|
||||
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
Editor editor = FileEditorManager.getInstance(file.getProject()).getSelectedTextEditor();
|
||||
LogicalPosition position = editor.offsetToLogicalPosition(startOffset);
|
||||
return position + ": '" + StringUtil.first(file.getText().substring(startOffset), 100, true) + "'";
|
||||
}
|
||||
}
|
||||
@@ -849,6 +849,10 @@
|
||||
<extensionPoint name="packageDependencies.visitor" beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<with attribute="implementationClass" implements="com.intellij.packageDependencies.DependencyVisitorFactory"/>
|
||||
</extensionPoint>
|
||||
|
||||
<extensionPoint name="lang.sliceProvider" beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<with attribute="implementationClass" implements="com.intellij.slicer.SliceLanguageSupportProvider"/>
|
||||
</extensionPoint>
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
||||
|
||||
|
||||
@@ -330,6 +330,11 @@
|
||||
<projectService serviceInterface="com.intellij.openapi.roots.impl.LibraryScopeCache"
|
||||
serviceImplementation="com.intellij.openapi.roots.impl.LibraryScopeCache"/>
|
||||
|
||||
<projectService serviceInterface="com.intellij.slicer.SliceToolwindowSettings"
|
||||
serviceImplementation="com.intellij.slicer.SliceToolwindowSettings"/>
|
||||
<projectService serviceInterface="com.intellij.slicer.SliceManager"
|
||||
serviceImplementation="com.intellij.slicer.SliceManager"/>
|
||||
|
||||
<moduleService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore" serviceImplementation="com.intellij.configurationStore.ModuleStoreImpl"/>
|
||||
<moduleService serviceImplementation="com.intellij.openapi.module.impl.ModuleImpl$DeprecatedModuleOptionManager"/>
|
||||
<moduleService serviceInterface="com.intellij.openapi.components.PathMacroManager" serviceImplementation="com.intellij.openapi.components.impl.ModulePathMacroManager"/>
|
||||
|
||||
@@ -533,10 +533,6 @@
|
||||
<projectService serviceInterface="com.intellij.usages.impl.rules.DirectoryGroupingRule"
|
||||
serviceImplementation="com.intellij.usages.impl.rules.PackageGroupingRule"/>
|
||||
|
||||
<projectService serviceInterface="com.intellij.slicer.SliceToolwindowSettings"
|
||||
serviceImplementation="com.intellij.slicer.SliceToolwindowSettings"/>
|
||||
<projectService serviceInterface="com.intellij.slicer.SliceManager"
|
||||
serviceImplementation="com.intellij.slicer.SliceManager"/>
|
||||
|
||||
<projectService serviceInterface="com.intellij.codeInspection.ex.EntryPointsManager"
|
||||
serviceImplementation="com.intellij.codeInspection.ex.EntryPointsManagerImpl"/>
|
||||
@@ -1114,6 +1110,8 @@
|
||||
<langCodeStyleSettingsProvider implementation="com.intellij.ide.JavaLanguageCodeStyleSettingsProvider"/>
|
||||
<lang.lineWrapStrategy language="JAVA" implementationClass="com.intellij.psi.formatter.java.JavaLineWrapPositionStrategy"/>
|
||||
|
||||
<lang.sliceProvider language="JAVA" implementationClass="com.intellij.slicer.JavaSliceProvider"/>
|
||||
|
||||
<stacktrace.fold substring="at java.awt.EventDispatchThread"/>
|
||||
<stacktrace.fold substring="at java.awt.Window.dispatchEventImpl("/>
|
||||
<stacktrace.fold substring="at java.awt.Container.dispatchEventImpl("/>
|
||||
|
||||
Reference in New Issue
Block a user