Merging php-slicing feature branch

This commit is contained in:
Shaverdova Elena
2015-09-17 21:10:49 +03:00
40 changed files with 564 additions and 224 deletions
@@ -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) {
@@ -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
+1
View File
@@ -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());
}
}
@@ -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,
@@ -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);
}
@@ -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>";
@@ -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>() {
@@ -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));
@@ -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,
@@ -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() {
@@ -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;
@@ -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"/>
+2 -4
View File
@@ -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("/>