mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
use AsyncTreeModel in inspection view
This commit is contained in:
@@ -22,14 +22,11 @@ import com.intellij.codeInspection.ex.DescriptorComposer;
|
||||
import com.intellij.codeInspection.ex.HTMLComposerImpl;
|
||||
import com.intellij.codeInspection.reference.*;
|
||||
import com.intellij.codeInspection.ui.InspectionToolPresentation;
|
||||
import com.intellij.codeInspection.ui.InspectionTreeNode;
|
||||
import com.intellij.codeInspection.ui.RefElementNode;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class DeadHTMLComposer extends HTMLComposerImpl {
|
||||
@@ -332,7 +329,7 @@ public class DeadHTMLComposer extends HTMLComposerImpl {
|
||||
}
|
||||
|
||||
private void appendCallesList(RefElement element, StringBuffer buf, Set<? super RefElement> mentionedElements, boolean appendCallees){
|
||||
final Set<RefElement> possibleChildren = getPossibleChildren(new RefElementNode(element, myToolPresentation), element);
|
||||
final Set<RefElement> possibleChildren = getPossibleChildren(element);
|
||||
if (!possibleChildren.isEmpty()) {
|
||||
if (appendCallees){
|
||||
appendHeading(buf, InspectionsBundle.message("inspection.export.results.callees"));
|
||||
@@ -359,16 +356,13 @@ public class DeadHTMLComposer extends HTMLComposerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<RefElement> getPossibleChildren(final RefElementNode refElementNode, RefElement refElement) {
|
||||
final TreeNode[] pathToRoot = refElementNode.getPath();
|
||||
private static Set<RefElement> getPossibleChildren(RefElement refElement) {
|
||||
if (!refElement.isValid()) return Collections.emptySet();
|
||||
|
||||
final HashSet<RefElement> newChildren = new HashSet<>();
|
||||
|
||||
if (!refElement.isValid()) return newChildren;
|
||||
|
||||
for (RefElement refCallee : refElement.getOutReferences()) {
|
||||
if (((RefElementImpl)refCallee).isSuspicious()) {
|
||||
if (notInPath(pathToRoot, refCallee)) newChildren.add(refCallee);
|
||||
newChildren.add(refCallee);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +373,7 @@ public class DeadHTMLComposer extends HTMLComposerImpl {
|
||||
if (!refMethod.isStatic() && !refMethod.isConstructor() && (aClass != null && !aClass.isAnonymous())) {
|
||||
for (RefMethod refDerived : refMethod.getDerivedMethods()) {
|
||||
if (((RefMethodImpl)refDerived).isSuspicious()) {
|
||||
if (notInPath(pathToRoot, refDerived)) newChildren.add(refDerived);
|
||||
newChildren.add(refDerived);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,25 +381,16 @@ public class DeadHTMLComposer extends HTMLComposerImpl {
|
||||
RefClass refClass = (RefClass) refElement;
|
||||
for (RefClass subClass : refClass.getSubClasses()) {
|
||||
if ((subClass.isInterface() || subClass.isAbstract()) && ((RefClassImpl)subClass).isSuspicious()) {
|
||||
if (notInPath(pathToRoot, subClass)) newChildren.add(subClass);
|
||||
newChildren.add(subClass);
|
||||
}
|
||||
}
|
||||
|
||||
if (refClass.getDefaultConstructor() instanceof RefImplicitConstructor) {
|
||||
Set<RefElement> fromConstructor = getPossibleChildren(refElementNode, refClass.getDefaultConstructor());
|
||||
Set<RefElement> fromConstructor = getPossibleChildren(refClass.getDefaultConstructor());
|
||||
newChildren.addAll(fromConstructor);
|
||||
}
|
||||
}
|
||||
|
||||
return newChildren;
|
||||
}
|
||||
|
||||
private static boolean notInPath(TreeNode[] pathToRoot, RefElement refChild) {
|
||||
for (TreeNode aPathToRoot : pathToRoot) {
|
||||
InspectionTreeNode node = (InspectionTreeNode)aPathToRoot;
|
||||
if (node instanceof RefElementNode && ((RefElementNode)node).getElement() == refChild) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-8
@@ -9,7 +9,6 @@ import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.reference.RefJavaElement;
|
||||
import com.intellij.codeInspection.ui.InspectionNode;
|
||||
import com.intellij.codeInspection.ui.InspectionResultsView;
|
||||
import com.intellij.codeInspection.ui.InspectionTreeNode;
|
||||
import com.intellij.codeInspection.util.RefFilter;
|
||||
@@ -40,7 +39,7 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation
|
||||
|
||||
@Override
|
||||
protected String getSeverityDelegateName() {
|
||||
return UnusedDeclarationInspection.SHORT_NAME;
|
||||
return UnusedDeclarationInspectionBase.SHORT_NAME;
|
||||
}
|
||||
|
||||
private class MoveEntriesToSuspicious extends QuickFixAction {
|
||||
@@ -84,12 +83,10 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createToolNode(@NotNull GlobalInspectionContextImpl context, @NotNull InspectionNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupByStructure) {
|
||||
myToolNode = node;
|
||||
public void patchToolNode(@NotNull InspectionTreeNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
boolean showStructure,
|
||||
boolean groupByStructure) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+23
-15
@@ -23,6 +23,7 @@ import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.AtomicNotNullLazyValue;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
@@ -73,6 +74,16 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
|
||||
private WeakUnreferencedFilter myFilter;
|
||||
private DeadHTMLComposer myComposer;
|
||||
private final AtomicNotNullLazyValue<InspectionToolWrapper> myDummyWrapper = new AtomicNotNullLazyValue<InspectionToolWrapper>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected InspectionToolWrapper compute() {
|
||||
InspectionToolWrapper toolWrapper = new GlobalInspectionToolWrapper(new DummyEntryPointsEP());
|
||||
toolWrapper.initialize(myContext);
|
||||
return toolWrapper;
|
||||
}
|
||||
};
|
||||
|
||||
@NonNls private static final String DELETE = "delete";
|
||||
@NonNls private static final String COMMENT = "comment";
|
||||
|
||||
@@ -410,24 +421,21 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createToolNode(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupByStructure) {
|
||||
final EntryPointsNode entryPointsNode = new EntryPointsNode(context);
|
||||
InspectionToolWrapper dummyToolWrapper = entryPointsNode.getToolWrapper();
|
||||
InspectionToolPresentation presentation = context.getPresentation(dummyToolWrapper);
|
||||
public void patchToolNode(@NotNull InspectionTreeNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
boolean showStructure,
|
||||
boolean groupByStructure) {
|
||||
InspectionTreeModel model = myContext.getView().getTree().getInspectionTreeModel();
|
||||
model.createCustomNode(myDummyWrapper.getValue(), () -> new EntryPointsNode(myDummyWrapper.getValue(), myContext, model), node);
|
||||
InspectionToolPresentation presentation = myContext.getPresentation(myDummyWrapper.getValue());
|
||||
presentation.updateContent();
|
||||
provider.appendToolNodeContent(context, entryPointsNode, node, showStructure, groupByStructure);
|
||||
myToolNode = entryPointsNode;
|
||||
provider.appendToolNodeContent(myContext, myDummyWrapper.getValue(), node, showStructure, groupByStructure);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public RefElementNode createRefNode(@Nullable RefEntity entity) {
|
||||
return new RefElementNode(entity, this) {
|
||||
public RefElementNode createRefNode(@Nullable RefEntity entity, @NotNull InspectionTreeModel model) {
|
||||
return new RefElementNode(entity, this, model) {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getTailText() {
|
||||
@@ -677,7 +685,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemsCount(@NotNull InspectionTree tree) {
|
||||
return 0;
|
||||
public boolean showProblemCount() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.deadCode.DummyEntryPointsEP;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
@@ -13,18 +11,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class EntryPointsNode extends InspectionNode {
|
||||
public EntryPointsNode(@NotNull GlobalInspectionContextImpl context) {
|
||||
super(createDummyWrapper(context), context.getCurrentProfile());
|
||||
}
|
||||
private volatile boolean myExcluded;
|
||||
|
||||
private static InspectionToolWrapper createDummyWrapper(@NotNull GlobalInspectionContextImpl context) {
|
||||
InspectionToolWrapper toolWrapper = new GlobalInspectionToolWrapper(new DummyEntryPointsEP());
|
||||
toolWrapper.initialize(context);
|
||||
return toolWrapper;
|
||||
public EntryPointsNode(@NotNull InspectionToolWrapper dummyWrapper,
|
||||
@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionTreeModel model) {
|
||||
super(dummyWrapper, context.getCurrentProfile(), model);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,7 +37,17 @@ public class EntryPointsNode extends InspectionNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemCount(boolean allowSuppressed) {
|
||||
return 0;
|
||||
public boolean isExcluded() {
|
||||
return myExcluded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void excludeElement() {
|
||||
myExcluded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void amnestyElement() {
|
||||
myExcluded = false;
|
||||
}
|
||||
}
|
||||
|
||||
+55
-48
@@ -13,8 +13,8 @@ import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
|
||||
import com.intellij.codeInspection.offlineViewer.OfflineViewParseUtil;
|
||||
import com.intellij.codeInspection.ui.InspectionResultsView;
|
||||
import com.intellij.codeInspection.ui.InspectionRootNode;
|
||||
import com.intellij.codeInspection.ui.InspectionTree;
|
||||
import com.intellij.codeInspection.ui.InspectionTreeNode;
|
||||
import com.intellij.codeInspection.ui.ProblemDescriptionNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
@@ -129,11 +129,13 @@ public class OfflineInspectionResultViewTest extends TestSourceBasedTestCase {
|
||||
InspectionTree tree = updateTree();
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
TreeUtil.expandAll(tree);
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-" + getProject() + "\n" +
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-InspectionViewTree\n" +
|
||||
" -Java\n" +
|
||||
" -Declaration redundancy\n" +
|
||||
" -unused\n" +
|
||||
" -Module: 'testOfflineWithInvalid'\n" +
|
||||
" -Unused declaration\n" +
|
||||
" Entry Points\n" +
|
||||
" -testOfflineWithInvalid\n" +
|
||||
" -<default>\n" +
|
||||
" -Test\n" +
|
||||
" -f()\n" +
|
||||
@@ -141,26 +143,26 @@ public class OfflineInspectionResultViewTest extends TestSourceBasedTestCase {
|
||||
" -b()\n" +
|
||||
" -anonymous (Runnable)\n" +
|
||||
" -run()\n" +
|
||||
" Variable <code>i</code> is never used.\n" +
|
||||
" Variable <code>r</code> is never used.\n" +
|
||||
" Variable 'i' is never used.\n" +
|
||||
" Variable 'r' is never used.\n" +
|
||||
" -ff()\n" +
|
||||
" Variable <code>a</code> is never used.\n" +
|
||||
" Variable <code>d</code> is never used.\n" +
|
||||
" Variable 'a' is never used.\n" +
|
||||
" Variable 'd' is never used.\n" +
|
||||
" -foo()\n" +
|
||||
" Variable <code>j</code> is never used.\n" +
|
||||
" Variable 'j' is never used.\n" +
|
||||
" -main(String[])\n" +
|
||||
" Variable <code>test</code> is never used.\n" +
|
||||
" Variable 'test' is never used.\n" +
|
||||
" -Probable bugs\n" +
|
||||
" -EqualsWithItself\n" +
|
||||
" -Module: 'testOfflineWithInvalid'\n" +
|
||||
" -'equals()' called on itself\n" +
|
||||
" -testOfflineWithInvalid\n" +
|
||||
" -<default>\n" +
|
||||
" -Test\n" +
|
||||
" -m()\n" +
|
||||
" 'equals()' called on itself\n" +
|
||||
" -null\n" +
|
||||
" -element no longer exists\n" +
|
||||
" '()' called on itself\n"
|
||||
);
|
||||
tree.setSelectionRow(28);
|
||||
tree.setSelectionRow(29);
|
||||
final ProblemDescriptionNode node = (ProblemDescriptionNode)tree.getSelectionModel().getSelectionPath().getLastPathComponent();
|
||||
assertFalse(node.isValid());
|
||||
}
|
||||
@@ -170,11 +172,13 @@ public class OfflineInspectionResultViewTest extends TestSourceBasedTestCase {
|
||||
InspectionTree tree = updateTree();
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
TreeUtil.expandAll(tree);
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-" + getProject() + "\n" +
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-InspectionViewTree\n" +
|
||||
" -Java\n" +
|
||||
" -Declaration redundancy\n" +
|
||||
" -unused\n" +
|
||||
" -Module: 'testOfflineView'\n" +
|
||||
" -Unused declaration\n" +
|
||||
" Entry Points\n" +
|
||||
" -testOfflineView\n" +
|
||||
" -<default>\n" +
|
||||
" -Test\n" +
|
||||
" -f()\n" +
|
||||
@@ -182,18 +186,18 @@ public class OfflineInspectionResultViewTest extends TestSourceBasedTestCase {
|
||||
" -b()\n" +
|
||||
" -anonymous (Runnable)\n" +
|
||||
" -run()\n" +
|
||||
" Variable <code>i</code> is never used.\n" +
|
||||
" Variable <code>r</code> is never used.\n" +
|
||||
" Variable 'i' is never used.\n" +
|
||||
" Variable 'r' is never used.\n" +
|
||||
" -ff()\n" +
|
||||
" Variable <code>a</code> is never used.\n" +
|
||||
" Variable <code>d</code> is never used.\n" +
|
||||
" Variable 'a' is never used.\n" +
|
||||
" Variable 'd' is never used.\n" +
|
||||
" -foo()\n" +
|
||||
" Variable <code>j</code> is never used.\n" +
|
||||
" Variable 'j' is never used.\n" +
|
||||
" -main(String[])\n" +
|
||||
" Variable <code>test</code> is never used.\n" +
|
||||
" Variable 'test' is never used.\n" +
|
||||
" -Probable bugs\n" +
|
||||
" -" + myDataFlowToolWrapper + "\n" +
|
||||
" -Module: 'testOfflineView'\n" +
|
||||
" -'equals()' called on itself\n" +
|
||||
" -testOfflineView\n" +
|
||||
" -<default>\n" +
|
||||
" -Test\n" +
|
||||
" -m()\n" +
|
||||
@@ -206,62 +210,64 @@ public class OfflineInspectionResultViewTest extends TestSourceBasedTestCase {
|
||||
tree = updateTree();
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
TreeUtil.expandAll(tree);
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-" + getProject() + "\n" +
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-InspectionViewTree\n" +
|
||||
" -Java\n" +
|
||||
" -Declaration redundancy\n" +
|
||||
" -unused\n" +
|
||||
" -Unused declaration\n" +
|
||||
" Entry Points\n" +
|
||||
" -Test\n" +
|
||||
" -f()\n" +
|
||||
" -D\n" +
|
||||
" -b()\n" +
|
||||
" -anonymous (Runnable)\n" +
|
||||
" -run()\n" +
|
||||
" Variable <code>i</code> is never used.\n" +
|
||||
" Variable <code>r</code> is never used.\n" +
|
||||
" Variable 'i' is never used.\n" +
|
||||
" Variable 'r' is never used.\n" +
|
||||
" -ff()\n" +
|
||||
" Variable <code>a</code> is never used.\n" +
|
||||
" Variable <code>d</code> is never used.\n" +
|
||||
" Variable 'a' is never used.\n" +
|
||||
" Variable 'd' is never used.\n" +
|
||||
" -foo()\n" +
|
||||
" Variable <code>j</code> is never used.\n" +
|
||||
" Variable 'j' is never used.\n" +
|
||||
" -main(String[])\n" +
|
||||
" Variable <code>test</code> is never used.\n" +
|
||||
" Variable 'test' is never used.\n" +
|
||||
" -Probable bugs\n" +
|
||||
" -EqualsWithItself\n" +
|
||||
" -'equals()' called on itself\n" +
|
||||
" -Test\n" +
|
||||
" 'equals()' called on itself\n" +
|
||||
" -Test2\n" +
|
||||
" 'equals()' called on itself\n"
|
||||
);
|
||||
TreeUtil.selectNode(tree, tree.getRoot());
|
||||
final InspectionTreeNode root = tree.getRoot();
|
||||
InspectionRootNode root = tree.getInspectionTreeModel().getRoot();
|
||||
root.excludeElement();
|
||||
TreeUtil.treeNodeTraverser(root).traverse().processEach(node -> {
|
||||
assertTrue(((InspectionTreeNode)node).isExcluded());
|
||||
tree.getInspectionTreeModel().traverse(root, node -> {
|
||||
assertTrue("node = " + node, node.isExcluded());
|
||||
return true;
|
||||
});
|
||||
myView.getGlobalInspectionContext().getUIOptions().FILTER_RESOLVED_ITEMS = false;
|
||||
tree = updateTree();
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-" + getProject() + "\n"
|
||||
PlatformTestUtil.assertTreeEqual(tree, "-InspectionViewTree\n"
|
||||
+ " -Java\n" +
|
||||
" -Declaration redundancy\n" +
|
||||
" -unused\n" +
|
||||
" -Unused declaration\n" +
|
||||
" Entry Points\n" +
|
||||
" -Test\n" +
|
||||
" -f()\n" +
|
||||
" -D\n" +
|
||||
" -b()\n" +
|
||||
" -anonymous (Runnable)\n" +
|
||||
" -run()\n" +
|
||||
" Variable <code>i</code> is never used.\n" +
|
||||
" Variable <code>r</code> is never used.\n" +
|
||||
" Variable 'i' is never used.\n" +
|
||||
" Variable 'r' is never used.\n" +
|
||||
" -ff()\n" +
|
||||
" Variable <code>a</code> is never used.\n" +
|
||||
" Variable <code>d</code> is never used.\n" +
|
||||
" Variable 'a' is never used.\n" +
|
||||
" Variable 'd' is never used.\n" +
|
||||
" -foo()\n" +
|
||||
" Variable <code>j</code> is never used.\n" +
|
||||
" Variable 'j' is never used.\n" +
|
||||
" -main(String[])\n" +
|
||||
" Variable <code>test</code> is never used.\n" +
|
||||
" Variable 'test' is never used.\n" +
|
||||
" -Probable bugs\n" +
|
||||
" -EqualsWithItself\n" +
|
||||
" -'equals()' called on itself\n" +
|
||||
" -Test\n" +
|
||||
" 'equals()' called on itself\n" +
|
||||
" -Test2\n" +
|
||||
@@ -269,10 +275,11 @@ public class OfflineInspectionResultViewTest extends TestSourceBasedTestCase {
|
||||
);
|
||||
}
|
||||
|
||||
private InspectionTree updateTree() {
|
||||
private InspectionTree updateTree() throws InterruptedException {
|
||||
myView.update();
|
||||
final InspectionTree tree = myView.getTree();
|
||||
TreeUtil.expandAll(tree);
|
||||
PlatformTestUtil.dispatchAllEventsInIdeEventQueue();
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ public class ViewOfflineResultsAction extends AnAction {
|
||||
context.setCurrentScope(scope);
|
||||
context.initializeTools(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||
final InspectionResultsView view = new InspectionResultsView(context,
|
||||
new OfflineInspectionRVContentProvider(resMap, project));
|
||||
new OfflineInspectionRVContentProvider(resMap));
|
||||
((RefManagerImpl)context.getRefManager()).startOfflineView();
|
||||
context.addView(view, title, true);
|
||||
view.update();
|
||||
|
||||
+5
-18
@@ -19,7 +19,6 @@ import com.intellij.codeInspection.reference.RefVisitor;
|
||||
import com.intellij.codeInspection.ui.DefaultInspectionToolPresentation;
|
||||
import com.intellij.codeInspection.ui.InspectionResultsView;
|
||||
import com.intellij.codeInspection.ui.InspectionToolPresentation;
|
||||
import com.intellij.codeInspection.ui.InspectionTreeState;
|
||||
import com.intellij.codeInspection.ui.actions.ExportHTMLAction;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.concurrency.JobLauncherImpl;
|
||||
@@ -83,7 +82,7 @@ import java.util.function.Predicate;
|
||||
|
||||
public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext {
|
||||
private static final int MAX_OPEN_GLOBAL_INSPECTION_XML_RESULT_FILES = SystemProperties.getIntProperty("max.open.global.inspection.xml.files", 50);
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl");
|
||||
private static final Logger LOG = Logger.getInstance(GlobalInspectionContextImpl.class);
|
||||
@SuppressWarnings("StaticNonFinalField")
|
||||
public static volatile boolean CREATE_VIEW_FORCE;
|
||||
public static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("Inspection Results", ToolWindowId.INSPECTION);
|
||||
@@ -97,7 +96,6 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
|
||||
@NotNull
|
||||
private AnalysisUIOptions myUIOptions;
|
||||
private InspectionTreeState myTreeState;
|
||||
|
||||
public GlobalInspectionContextImpl(@NotNull Project project, @NotNull NotNullLazyValue<? extends ContentManager> contentManager) {
|
||||
super(project);
|
||||
@@ -110,10 +108,6 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return myContentManager.getValue();
|
||||
}
|
||||
|
||||
public void setTreeState(InspectionTreeState treeState) {
|
||||
myTreeState = treeState;
|
||||
}
|
||||
|
||||
public void addView(@NotNull InspectionResultsView view,
|
||||
@NotNull String title,
|
||||
boolean isOffline) {
|
||||
@@ -134,9 +128,6 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
if (!isOffline) {
|
||||
myView.setUpdating(true);
|
||||
}
|
||||
if (myTreeState != null) {
|
||||
myView.getTree().setTreeState(myTreeState);
|
||||
}
|
||||
myContent = ContentFactory.SERVICE.getInstance().createContent(view, title, false);
|
||||
myContent.setHelpId(InspectionResultsView.HELP_ID);
|
||||
myContent.setDisposer(myView);
|
||||
@@ -387,7 +378,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
LOG.info("Code inspection finished. Took " + elapsed + "ms");
|
||||
if (getProject().isDisposed()) return;
|
||||
|
||||
InspectionResultsView newView = myView == null ? new InspectionResultsView(this, createContentProvider()) : null;
|
||||
InspectionResultsView newView = myView == null ? new InspectionResultsView(this, new InspectionRVContentProviderImpl()) : null;
|
||||
if (!(myView == null ? newView : myView).hasProblems()) {
|
||||
NOTIFICATION_GROUP.createNotification(InspectionsBundle.message("inspection.no.problems.message",
|
||||
scope.getFileCount(),
|
||||
@@ -770,7 +761,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
if (getCurrentScope() == null) return;
|
||||
InspectionResultsView view = getView();
|
||||
if (view == null) {
|
||||
view = new InspectionResultsView(this, createContentProvider());
|
||||
view = new InspectionResultsView(this, new InspectionRVContentProviderImpl());
|
||||
addView(view);
|
||||
}
|
||||
}, x -> getCurrentScope() == null);
|
||||
@@ -913,7 +904,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
|
||||
public void refreshViews() {
|
||||
if (myView != null) {
|
||||
myView.getTree().queueUpdate();
|
||||
myView.getTree().getInspectionTreeModel().reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1092,15 +1083,11 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return myViewClosed;
|
||||
}
|
||||
|
||||
private InspectionRVContentProvider createContentProvider() {
|
||||
return new InspectionRVContentProviderImpl(getProject());
|
||||
}
|
||||
|
||||
private void addProblemsToView(List<Tools> tools) {
|
||||
if (ApplicationManager.getApplication().isHeadlessEnvironment() && !CREATE_VIEW_FORCE) {
|
||||
return;
|
||||
}
|
||||
if (myView == null && !ReadAction.compute(() -> InspectionResultsView.hasProblems(tools, this, createContentProvider())).booleanValue()) {
|
||||
if (myView == null && !ReadAction.compute(() -> InspectionResultsView.hasProblems(tools, this, new InspectionRVContentProviderImpl())).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
initializeViewIfNeed().doWhenDone(() -> myView.addTools(tools));
|
||||
|
||||
+68
-263
@@ -14,8 +14,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -31,14 +29,11 @@ import javax.swing.tree.TreePath;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public abstract class InspectionRVContentProvider {
|
||||
private static final Logger LOG = Logger.getInstance(InspectionRVContentProvider.class);
|
||||
private final Project myProject;
|
||||
|
||||
public InspectionRVContentProvider(@NotNull Project project) {
|
||||
myProject = project;
|
||||
public InspectionRVContentProvider() {
|
||||
}
|
||||
|
||||
protected static class RefEntityContainer<Descriptor> {
|
||||
@@ -51,18 +46,22 @@ public abstract class InspectionRVContentProvider {
|
||||
myDescriptors = descriptors;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RefEntityContainer<Descriptor> getOwner() {
|
||||
if (myEntity == null) return null;
|
||||
final RefEntity entity = myEntity.getOwner();
|
||||
return entity instanceof RefElement && !(entity instanceof RefDirectory)
|
||||
? new RefEntityContainer<>(entity, myDescriptors)
|
||||
: null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RefElementNode createNode(@NotNull InspectionToolPresentation presentation) {
|
||||
return ReadAction.compute(() -> presentation.createRefNode(myEntity));
|
||||
public RefElementNode createNode(@NotNull InspectionToolPresentation presentation,
|
||||
InspectionTreeModel model,
|
||||
InspectionTreeNode topParent,
|
||||
boolean showStructure) {
|
||||
RefEntityContainer<Descriptor> owner = getOwner();
|
||||
InspectionTreeNode parent;
|
||||
if (owner == null) {
|
||||
parent = topParent;
|
||||
} else {
|
||||
parent = owner.createNode(presentation, model, topParent, showStructure);
|
||||
if (!showStructure) {
|
||||
return (RefElementNode)parent;
|
||||
}
|
||||
}
|
||||
return model.createRefElementNode(myEntity, () -> presentation.createRefNode(myEntity, model), parent);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -71,15 +70,18 @@ public abstract class InspectionRVContentProvider {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getModule() {
|
||||
protected String getModuleName() {
|
||||
final RefModule refModule = myEntity instanceof RefElement
|
||||
? ((RefElement)myEntity).getModule()
|
||||
: myEntity instanceof RefModule ? (RefModule)myEntity : null;
|
||||
return refModule != null ? refModule.getName() : null;
|
||||
}
|
||||
|
||||
boolean areEqual(final @NotNull RefEntity o1, final @NotNull RefEntity o2) {
|
||||
return Comparing.equal(o1, o2);
|
||||
@Nullable
|
||||
public Module getModule(Project project) {
|
||||
String name = getModuleName();
|
||||
if (name == null) return null;
|
||||
return ReadAction.compute(() -> ModuleManager.getInstance(project).findModuleByName(name));
|
||||
}
|
||||
|
||||
boolean supportStructure() {
|
||||
@@ -89,6 +91,15 @@ public abstract class InspectionRVContentProvider {
|
||||
public Descriptor[] getDescriptors() {
|
||||
return myDescriptors;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RefEntityContainer<Descriptor> getOwner() {
|
||||
if (myEntity == null) return null;
|
||||
final RefEntity entity = myEntity.getOwner();
|
||||
return entity instanceof RefElement && !(entity instanceof RefDirectory)
|
||||
? new RefEntityContainer<>(entity, myDescriptors)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean checkReportedProblems(@NotNull GlobalInspectionContextImpl context, @NotNull InspectionToolWrapper toolWrapper);
|
||||
@@ -197,15 +208,14 @@ public abstract class InspectionRVContentProvider {
|
||||
.toArray(StackTraceElement.class);
|
||||
}
|
||||
|
||||
public InspectionNode appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionNode toolNode,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity) {
|
||||
InspectionToolWrapper wrapper = toolNode.getToolWrapper();
|
||||
public void appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionToolWrapper wrapper,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity) {
|
||||
InspectionToolPresentation presentation = context.getPresentation(wrapper);
|
||||
Map<String, Set<RefEntity>> content = presentation.getContent();
|
||||
return appendToolNodeContent(context, toolNode, parentNode, showStructure, groupBySeverity, content, entity -> {
|
||||
appendToolNodeContent(context, wrapper, parentNode, showStructure, groupBySeverity, content, entity -> {
|
||||
if (context.getUIOptions().FILTER_RESOLVED_ITEMS) {
|
||||
return presentation.isExcluded(entity) ? null : presentation.getProblemElements().get(entity);
|
||||
} else {
|
||||
@@ -221,19 +231,18 @@ public abstract class InspectionRVContentProvider {
|
||||
});
|
||||
}
|
||||
|
||||
public abstract InspectionNode appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionNode toolNode,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
final boolean showStructure,
|
||||
boolean groupBySeverity,
|
||||
@NotNull Map<String, Set<RefEntity>> contents,
|
||||
@NotNull Function<? super RefEntity, CommonProblemDescriptor[]> problems);
|
||||
public abstract void appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionToolWrapper wrapper,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
final boolean showStructure,
|
||||
boolean groupBySeverity,
|
||||
@NotNull Map<String, Set<RefEntity>> contents,
|
||||
@NotNull Function<? super RefEntity, CommonProblemDescriptor[]> problems);
|
||||
|
||||
protected abstract void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionToolWrapper toolWrapper,
|
||||
@NotNull RefEntityContainer container,
|
||||
@NotNull InspectionTreeNode pNode,
|
||||
final boolean canPackageRepeat);
|
||||
@NotNull InspectionTreeNode parent);
|
||||
|
||||
public boolean isContentLoaded() {
|
||||
return true;
|
||||
@@ -241,241 +250,37 @@ public abstract class InspectionRVContentProvider {
|
||||
|
||||
protected <T> void buildTree(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull Map<String, Set<T>> packageContents,
|
||||
final boolean canPackageRepeat,
|
||||
@NotNull InspectionToolWrapper toolWrapper,
|
||||
@NotNull Function<? super T, ? extends RefEntityContainer<?>> computeContainer,
|
||||
final boolean showStructure,
|
||||
final UnaryOperator<? super InspectionTreeNode> createdNodesConsumer) {
|
||||
final Map<String, Map<String, InspectionPackageNode>> module2PackageMap = new HashMap<>();
|
||||
boolean supportStructure = showStructure;
|
||||
final MultiMap<InspectionPackageNode, RefEntityContainer<?>> packageDescriptors = new MultiMap<>();
|
||||
for (String packageName : packageContents.keySet()) {
|
||||
final Set<T> elements = packageContents.get(packageName);
|
||||
for (T userObject : elements) {
|
||||
final RefEntityContainer container = computeContainer.apply(userObject);
|
||||
supportStructure &= container.supportStructure();
|
||||
final String moduleName = showStructure ? container.getModule() : null;
|
||||
Map<String, InspectionPackageNode> packageNodes = module2PackageMap.get(moduleName);
|
||||
if (packageNodes == null) {
|
||||
packageNodes = new HashMap<>();
|
||||
module2PackageMap.put(moduleName, packageNodes);
|
||||
}
|
||||
InspectionPackageNode pNode = packageNodes.get(packageName);
|
||||
if (pNode == null) {
|
||||
pNode = new InspectionPackageNode(packageName);
|
||||
packageNodes.put(packageName, pNode);
|
||||
}
|
||||
|
||||
packageDescriptors.putValue(pNode, container);
|
||||
boolean showStructure,
|
||||
final InspectionTreeNode parent,
|
||||
InspectionTreeModel model) {
|
||||
MultiMap<String, RefEntityContainer> evaluatedDescriptors = MultiMap.create();
|
||||
for (Map.Entry<String, Set<T>> entry : packageContents.entrySet()) {
|
||||
String packageName = entry.getKey();
|
||||
for (T problemDescriptor : entry.getValue()) {
|
||||
RefEntityContainer<?> container = computeContainer.apply(problemDescriptor);
|
||||
evaluatedDescriptors.putValue(packageName, container);
|
||||
showStructure &= container.supportStructure();
|
||||
}
|
||||
}
|
||||
|
||||
if (supportStructure) {
|
||||
final HashMap<String, InspectionModuleNode> moduleNodes = new HashMap<>();
|
||||
for (final String moduleName : module2PackageMap.keySet()) {
|
||||
final Map<String, InspectionPackageNode> packageNodes = module2PackageMap.get(moduleName);
|
||||
InspectionModuleNode moduleNode = moduleNodes.get(moduleName);
|
||||
|
||||
if (moduleNode == null) {
|
||||
if (moduleName != null) {
|
||||
final Module module = ReadAction.compute(() -> ModuleManager.getInstance(myProject).findModuleByName(moduleName));
|
||||
if (module != null) {
|
||||
moduleNode = new InspectionModuleNode(module);
|
||||
moduleNodes.put(moduleName, moduleNode);
|
||||
moduleNode = (InspectionModuleNode)createdNodesConsumer.apply(moduleNode);
|
||||
}
|
||||
else { //module content was removed ?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (InspectionPackageNode packageNode : packageNodes.values()) {
|
||||
for (RefEntityContainer<?> container : packageDescriptors.get(packageNode)) {
|
||||
appendDescriptor(context, toolWrapper, container, packageNode, canPackageRepeat);
|
||||
}
|
||||
createdNodesConsumer.apply(packageNode);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
moduleNode = (InspectionModuleNode)createdNodesConsumer.apply(moduleNode);
|
||||
}
|
||||
for (InspectionPackageNode packageNode : packageNodes.values()) {
|
||||
if (packageNode.getPackageName() != null) {
|
||||
Collection<RefEntityContainer<?>> objectContainers = packageDescriptors.get(packageNode);
|
||||
packageNode = (InspectionPackageNode)merge(packageNode, moduleNode, true);
|
||||
for (RefEntityContainer<?> container : objectContainers) {
|
||||
appendDescriptor(context, toolWrapper, container, packageNode, canPackageRepeat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (RefEntityContainer<?> container : packageDescriptors.get(packageNode)) {
|
||||
appendDescriptor(context, toolWrapper, container, moduleNode, canPackageRepeat);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, Collection<RefEntityContainer>> entry : evaluatedDescriptors.entrySet()) {
|
||||
for (RefEntityContainer container : entry.getValue()) {
|
||||
InspectionTreeNode currentParent = parent;
|
||||
if (showStructure) {
|
||||
String packageName = entry.getKey();
|
||||
Module module = container.getModule(context.getProject());
|
||||
InspectionTreeNode moduleNode = module != null ? model.createModuleNode(module, parent) : null;
|
||||
currentParent = model.createPackageNode(packageName, moduleNode == null ? parent : moduleNode);
|
||||
}
|
||||
RefElementNode node = container.createNode(context.getPresentation(toolWrapper),
|
||||
model,
|
||||
currentParent,
|
||||
showStructure || HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME.equals(toolWrapper.getShortName()));
|
||||
appendDescriptor(context, toolWrapper, container, node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Map<String, InspectionPackageNode> packageNodes : module2PackageMap.values()) {
|
||||
for (InspectionPackageNode pNode : packageNodes.values()) {
|
||||
for (RefEntityContainer<?> container : packageDescriptors.get(pNode)) {
|
||||
appendDescriptor(context, toolWrapper, container, pNode, canPackageRepeat);
|
||||
}
|
||||
final int count = pNode.getChildCount();
|
||||
final ArrayList<TreeNode> childNodes = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
childNodes.add(pNode.getChildAt(i));
|
||||
}
|
||||
for (TreeNode childNode: childNodes) {
|
||||
if (childNode instanceof ProblemDescriptionNode) {
|
||||
createdNodesConsumer.apply(pNode);
|
||||
break;
|
||||
}
|
||||
LOG.assertTrue(childNode instanceof RefElementNode, childNode.getClass().getName());
|
||||
final RefElementNode elementNode = (RefElementNode)childNode;
|
||||
final Set<RefElementNode> parentNodes = new LinkedHashSet<>();
|
||||
if (pNode.getPackageName() != null) {
|
||||
parentNodes.add(elementNode);
|
||||
} else {
|
||||
boolean hasElementNodeUnder = true;
|
||||
for(int e = 0; e < elementNode.getChildCount(); e++) {
|
||||
final TreeNode grandChildNode = elementNode.getChildAt(e);
|
||||
if (grandChildNode instanceof ProblemDescriptionNode) {
|
||||
hasElementNodeUnder = false;
|
||||
break;
|
||||
}
|
||||
LOG.assertTrue(grandChildNode instanceof RefElementNode);
|
||||
parentNodes.add((RefElementNode)grandChildNode);
|
||||
}
|
||||
if (!hasElementNodeUnder) {
|
||||
createdNodesConsumer.apply(elementNode);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//allow unused declaration to have structure at file level even when there are unused parameters
|
||||
if (!HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME.equals(toolWrapper.getShortName())) {
|
||||
for (RefElementNode parentNode : parentNodes) {
|
||||
final List<ProblemDescriptionNode> nodes = new ArrayList<>();
|
||||
TreeUtil.traverse(parentNode, node -> {
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
nodes.add((ProblemDescriptionNode)node);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (nodes.isEmpty()) continue;
|
||||
parentNode.removeAllChildren();
|
||||
for (ProblemDescriptionNode node : nodes) {
|
||||
parentNode.insertByOrder(node, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (RefElementNode node : parentNodes) {
|
||||
createdNodesConsumer.apply(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static RefElementNode addNodeToParent(@NotNull RefEntityContainer container,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
final InspectionTreeNode parentNode) {
|
||||
final RefElementNode nodeToBeAdded = container.createNode(presentation);
|
||||
final Ref<Boolean> firstLevel = new Ref<>(true);
|
||||
RefElementNode prevNode = null;
|
||||
final Ref<RefElementNode> result = new Ref<>();
|
||||
while (true) {
|
||||
final RefElementNode currentNode = firstLevel.get() ? nodeToBeAdded : container.createNode(presentation);
|
||||
final RefEntityContainer finalContainer = container;
|
||||
final RefElementNode finalPrevNode = prevNode;
|
||||
TreeUtil.treeNodeTraverser(parentNode).traverse(TreeTraversal.PRE_ORDER_DFS).processEach(node -> {
|
||||
if (node instanceof RefElementNode) {
|
||||
final RefElementNode refElementNode = (RefElementNode)node;
|
||||
final RefEntity userObject = finalContainer.getRefEntity();
|
||||
final RefEntity object = refElementNode.getElement();
|
||||
if (userObject != null &&
|
||||
object != null &&
|
||||
(userObject.getClass().equals(object.getClass())) &&
|
||||
finalContainer.areEqual(object, userObject)) {
|
||||
if (firstLevel.get()) {
|
||||
result.set(refElementNode);
|
||||
}
|
||||
else {
|
||||
refElementNode.insertByOrder(finalPrevNode, false);
|
||||
result.set(nodeToBeAdded);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if(!result.isNull()) return result.get();
|
||||
|
||||
if (!firstLevel.get()) {
|
||||
currentNode.insertByOrder(prevNode, false);
|
||||
}
|
||||
final RefEntityContainer owner = container.getOwner();
|
||||
if (owner == null) {
|
||||
parentNode.insertByOrder(currentNode, false);
|
||||
return nodeToBeAdded;
|
||||
}
|
||||
container = owner;
|
||||
prevNode = currentNode;
|
||||
firstLevel.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
//class cast suppression
|
||||
public static InspectionTreeNode merge(InspectionTreeNode child, InspectionTreeNode parent, boolean merge) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (merge) {
|
||||
for (int i = 0; i < parent.getChildCount(); i++) {
|
||||
InspectionTreeNode current = (InspectionTreeNode)parent.getChildAt(i);
|
||||
if (child.getClass() != current.getClass()) {
|
||||
continue;
|
||||
}
|
||||
if (current instanceof InspectionPackageNode) {
|
||||
if (((InspectionPackageNode)current).getPackageName().compareTo(((InspectionPackageNode)child).getPackageName()) == 0) {
|
||||
processDepth(child, current);
|
||||
return current;
|
||||
}
|
||||
}
|
||||
else if (current instanceof RefElementNode) {
|
||||
if (InspectionResultsViewComparator.getInstance().compare(current, child) == 0) {
|
||||
processDepth(child, current);
|
||||
return current;
|
||||
}
|
||||
}
|
||||
else if (current instanceof InspectionNode) {
|
||||
if (((InspectionNode)current).getToolWrapper().getShortName().compareTo(((InspectionNode)child).getToolWrapper().getShortName()) == 0) {
|
||||
processDepth(child, current);
|
||||
return current;
|
||||
}
|
||||
}
|
||||
else if (current instanceof InspectionModuleNode) {
|
||||
if (((InspectionModuleNode)current).getName().compareTo(((InspectionModuleNode)child).getName()) == 0) {
|
||||
processDepth(child, current);
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent.insertByOrder(child, false);
|
||||
});
|
||||
}
|
||||
|
||||
private static void processDepth(final InspectionTreeNode child, final InspectionTreeNode current) {
|
||||
InspectionTreeNode[] children = new InspectionTreeNode[child.getChildCount()];
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
children[i] = (InspectionTreeNode)child.getChildAt(i);
|
||||
}
|
||||
for (InspectionTreeNode node : children) {
|
||||
merge(node, current, true);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+19
-27
@@ -11,8 +11,6 @@ import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.reference.RefUtil;
|
||||
import com.intellij.codeInspection.ui.*;
|
||||
import com.intellij.codeInspection.ui.util.SynchronizedBidiMultiMap;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -29,10 +27,6 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class InspectionRVContentProviderImpl extends InspectionRVContentProvider {
|
||||
public InspectionRVContentProviderImpl(final Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkReportedProblems(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull final InspectionToolWrapper toolWrapper) {
|
||||
@@ -81,52 +75,50 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionNode appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull final InspectionNode toolNode,
|
||||
@NotNull final InspectionTreeNode parentNode,
|
||||
final boolean showStructure,
|
||||
boolean groupBySeverity,
|
||||
@NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull final Function<? super RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
final InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
|
||||
InspectionNode mergedToolNode = (InspectionNode)merge(toolNode, parentNode, !groupBySeverity);
|
||||
public void appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull final InspectionToolWrapper wrapper,
|
||||
@NotNull final InspectionTreeNode toolNode,
|
||||
final boolean showStructure,
|
||||
boolean groupBySeverity,
|
||||
@NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull final Function<? super RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
|
||||
InspectionResultsView view = context.getView();
|
||||
|
||||
buildTree(context,
|
||||
contents,
|
||||
false,
|
||||
toolWrapper,
|
||||
wrapper,
|
||||
refElement -> new RefEntityContainer<>(refElement, problems.apply(refElement)),
|
||||
showStructure,
|
||||
node -> merge(node, mergedToolNode, true));
|
||||
return mergedToolNode;
|
||||
toolNode,
|
||||
view.getTree().getInspectionTreeModel());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull final InspectionToolWrapper toolWrapper,
|
||||
@NotNull final RefEntityContainer container,
|
||||
@NotNull final InspectionTreeNode pNode,
|
||||
final boolean canPackageRepeat) {
|
||||
@NotNull final InspectionTreeNode parent) {
|
||||
final RefEntity refElement = container.getRefEntity();
|
||||
InspectionTreeModel model = context.getView().getTree().getInspectionTreeModel();
|
||||
InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
|
||||
final CommonProblemDescriptor[] problems = ((RefEntityContainer<CommonProblemDescriptor>)container).getDescriptors();
|
||||
if (problems != null && problems.length != 0) {
|
||||
final RefElementNode elemNode = addNodeToParent(container, presentation, pNode);
|
||||
for (CommonProblemDescriptor problem : problems) {
|
||||
assert problem != null;
|
||||
elemNode.insertByOrder(ReadAction.compute(() -> new ProblemDescriptionNode(refElement, problem, presentation)), false);
|
||||
elemNode.setProblem(elemNode.getChildCount() == 1 ? problems[0] : null);
|
||||
model.createProblemDescriptorNode(refElement, problem, presentation, parent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (canPackageRepeat && pNode instanceof InspectionPackageNode) {
|
||||
final Set<RefEntity> currentElements = presentation.getContent().get(((InspectionPackageNode) pNode).getPackageName());
|
||||
if (false) {
|
||||
final Set<RefEntity> currentElements = presentation.getContent().get(((InspectionPackageNode) parent).getPackageName());
|
||||
if (currentElements != null) {
|
||||
final Set<RefEntity> currentEntities = new HashSet<>(currentElements);
|
||||
if (RefUtil.contains(refElement, currentEntities)) return;
|
||||
}
|
||||
}
|
||||
addNodeToParent(container, presentation, pNode);
|
||||
//TODO don't understand
|
||||
//addNodeToParent(container, presentation, parent, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
|
||||
@@ -110,10 +111,11 @@ public class QuickFixAction extends AnAction implements CustomComponentAction {
|
||||
try {
|
||||
Ref<List<CommonProblemDescriptor[]>> descriptors = Ref.create();
|
||||
Set<VirtualFile> readOnlyFiles = new THashSet<>();
|
||||
TreePath[] paths = tree.getSelectionPaths();
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> ReadAction.run(() -> {
|
||||
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
indicator.setText("Checking problem descriptors...");
|
||||
descriptors.set(tree.getSelectedDescriptorPacks(true, readOnlyFiles, false));
|
||||
descriptors.set(tree.getSelectedDescriptorPacks(true, readOnlyFiles, false, paths));
|
||||
}), InspectionsBundle.message("preparing.for.apply.fix"), true, e.getProject())) {
|
||||
return;
|
||||
}
|
||||
|
||||
+16
-15
@@ -41,19 +41,6 @@ public class InspectionTreeHtmlWriter {
|
||||
serializeTreeToHtml();
|
||||
}
|
||||
|
||||
private void traverseInspectionTree(final InspectionTreeNode node,
|
||||
final Consumer<? super InspectionTreeNode> preAction,
|
||||
final Consumer<? super InspectionTreeNode> postAction) {
|
||||
if (node.isExcluded()) {
|
||||
return;
|
||||
}
|
||||
preAction.accept(node);
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
traverseInspectionTree((InspectionTreeNode)node.getChildAt(i), preAction, postAction);
|
||||
}
|
||||
postAction.accept(node);
|
||||
}
|
||||
|
||||
private void serializeTreeToHtml() {
|
||||
appendHeader();
|
||||
appendTree((builder) -> {
|
||||
@@ -68,7 +55,8 @@ public class InspectionTreeHtmlWriter {
|
||||
builder.append(escapeNonBreakingSymbols(text));
|
||||
}
|
||||
};
|
||||
traverseInspectionTree(myTree.getRoot(),
|
||||
InspectionTreeModel model = myTree.getInspectionTreeModel();
|
||||
traverseInspectionTree(model.getRoot(),
|
||||
(n) -> {
|
||||
final int nodeId = System.identityHashCode(n);
|
||||
builder
|
||||
@@ -104,6 +92,19 @@ public class InspectionTreeHtmlWriter {
|
||||
InspectionTreeHtmlExportResources.copyInspectionReportResources(myOutputDir);
|
||||
}
|
||||
|
||||
private static void traverseInspectionTree(InspectionTreeNode node,
|
||||
Consumer<? super InspectionTreeNode> preAction,
|
||||
Consumer<? super InspectionTreeNode> postAction) {
|
||||
if (node.isExcluded()) {
|
||||
return;
|
||||
}
|
||||
preAction.accept(node);
|
||||
for (InspectionTreeNode child : node.getChildren()) {
|
||||
traverseInspectionTree(child, preAction, postAction);
|
||||
}
|
||||
postAction.accept(node);
|
||||
}
|
||||
|
||||
private String convertNodeToHtml(InspectionTreeNode node) {
|
||||
if (node instanceof InspectionRootNode) {
|
||||
return "<b>'" + escapeNonBreakingSymbols(node) + "' project</b>";
|
||||
@@ -139,7 +140,7 @@ public class InspectionTreeHtmlWriter {
|
||||
return sb.toString();
|
||||
}
|
||||
else if (node instanceof RefElementNode) {
|
||||
final String type = myManager.getType((RefEntity)node.getUserObject());
|
||||
final String type = myManager.getType(((RefElementNode)node).getElement());
|
||||
return type + " <b>" + node.toString() + "</b>";
|
||||
}
|
||||
else if (node instanceof InspectionNode) {
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
class OfflineDescriptorResolveResult {
|
||||
public class OfflineDescriptorResolveResult {
|
||||
private static final Logger LOG = Logger.getInstance(OfflineDescriptorResolveResult.class);
|
||||
private final RefEntity myResolvedEntity;
|
||||
private final CommonProblemDescriptor myResolvedDescriptor;
|
||||
|
||||
+17
-28
@@ -10,11 +10,8 @@ import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.*;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import java.util.HashSet;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -27,9 +24,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
private final Map<String, Map<OfflineProblemDescriptor, OfflineDescriptorResolveResult>> myResolvedDescriptor =
|
||||
FactoryMap.create(key -> new THashMap<>());
|
||||
|
||||
public OfflineInspectionRVContentProvider(@NotNull Map<String, Map<String, Set<OfflineProblemDescriptor>>> content,
|
||||
@NotNull Project project) {
|
||||
super(project);
|
||||
public OfflineInspectionRVContentProvider(@NotNull Map<String, Map<String, Set<OfflineProblemDescriptor>>> content) {
|
||||
myContent = content;
|
||||
}
|
||||
|
||||
@@ -59,33 +54,28 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionNode appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionNode toolNode,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity, @NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull Function<? super RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
|
||||
final Map<String, Set<OfflineProblemDescriptor>> filteredContent = getFilteredContent(context, toolWrapper);
|
||||
public void appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionToolWrapper wrapper,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity, @NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull Function<? super RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
final Map<String, Set<OfflineProblemDescriptor>> filteredContent = getFilteredContent(context, wrapper);
|
||||
InspectionResultsView view = context.getView();
|
||||
if (filteredContent != null && !filteredContent.values().isEmpty()) {
|
||||
parentNode.insertByOrder(toolNode, false);
|
||||
buildTree(context, filteredContent, false, toolWrapper, descriptor -> {
|
||||
buildTree(context, filteredContent, wrapper, descriptor -> {
|
||||
final RefEntity element = descriptor.getRefElement(context.getRefManager());
|
||||
return new RefEntityContainer<OfflineProblemDescriptor>(element, new OfflineProblemDescriptor[] {descriptor}) {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getModule() {
|
||||
final String module = super.getModule();
|
||||
protected String getModuleName() {
|
||||
final String module = super.getModuleName();
|
||||
return module == null ? descriptor.getModuleName() : module;
|
||||
}
|
||||
};
|
||||
}, showStructure,
|
||||
(newChild) -> {
|
||||
toolNode.insertByOrder(newChild, false);
|
||||
return newChild;
|
||||
});
|
||||
parentNode, view.getTree().getInspectionTreeModel());
|
||||
}
|
||||
return toolNode;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -140,10 +130,9 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
protected void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull final InspectionToolWrapper toolWrapper,
|
||||
@NotNull final RefEntityContainer container,
|
||||
@NotNull final InspectionTreeNode packageNode,
|
||||
final boolean canPackageRepeat) {
|
||||
@NotNull final InspectionTreeNode parent) {
|
||||
InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
|
||||
final RefElementNode elemNode = addNodeToParent(container, presentation, packageNode);
|
||||
InspectionTreeModel model = context.getView().getTree().getInspectionTreeModel();
|
||||
for (OfflineProblemDescriptor descriptor : ((RefEntityContainer<OfflineProblemDescriptor>)container).getDescriptors()) {
|
||||
final OfflineDescriptorResolveResult resolveResult = myResolvedDescriptor.get(toolWrapper.getShortName())
|
||||
.computeIfAbsent(descriptor, d -> OfflineDescriptorResolveResult.resolve(d, toolWrapper, presentation));
|
||||
@@ -151,9 +140,9 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
CommonProblemDescriptor resolvedDescriptor = resolveResult.getResolvedDescriptor();
|
||||
if (resolvedEntity != null && resolvedDescriptor != null) {
|
||||
presentation.getProblemElements().put(resolvedEntity, resolvedDescriptor);
|
||||
elemNode.insertByOrder(ReadAction.compute(() -> new ProblemDescriptionNode(resolvedEntity, resolvedDescriptor, presentation)), true);
|
||||
model.createProblemDescriptorNode(resolvedEntity, resolvedDescriptor, presentation, parent);
|
||||
} else {
|
||||
elemNode.insertByOrder(ReadAction.compute(() -> OfflineProblemDescriptorNode.create(descriptor, resolveResult, presentation)), true);
|
||||
model.createOfflineProblemDescriptorNode(descriptor, resolveResult, presentation, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-13
@@ -7,37 +7,39 @@ package com.intellij.codeInspection.offlineViewer;
|
||||
import com.intellij.codeInspection.ProblemDescriptorUtil;
|
||||
import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
|
||||
import com.intellij.codeInspection.ui.InspectionToolPresentation;
|
||||
import com.intellij.codeInspection.ui.InspectionTreeModel;
|
||||
import com.intellij.codeInspection.ui.ProblemDescriptionNode;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OfflineProblemDescriptorNode extends ProblemDescriptionNode {
|
||||
private final OfflineDescriptorResolveResult myDescriptorResolveResult;
|
||||
private final OfflineProblemDescriptor myOfflineDescriptor;
|
||||
|
||||
private OfflineProblemDescriptorNode(OfflineDescriptorResolveResult descriptorResolveResult,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
@NotNull OfflineProblemDescriptor offlineDescriptor) {
|
||||
super(descriptorResolveResult.getResolvedEntity(), descriptorResolveResult.getResolvedDescriptor(), presentation, offlineDescriptor::getLine);
|
||||
public OfflineProblemDescriptorNode(OfflineDescriptorResolveResult descriptorResolveResult,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
@NotNull OfflineProblemDescriptor offlineDescriptor,
|
||||
InspectionTreeModel model) {
|
||||
super(descriptorResolveResult.getResolvedEntity(), descriptorResolveResult.getResolvedDescriptor(), presentation, offlineDescriptor::getLine, model);
|
||||
myDescriptorResolveResult = descriptorResolveResult;
|
||||
if (descriptorResolveResult.getResolvedDescriptor() == null) {
|
||||
setUserObject(offlineDescriptor);
|
||||
}
|
||||
myOfflineDescriptor = offlineDescriptor;
|
||||
}
|
||||
|
||||
static OfflineProblemDescriptorNode create(@NotNull OfflineProblemDescriptor offlineDescriptor,
|
||||
@NotNull OfflineDescriptorResolveResult resolveResult,
|
||||
@NotNull InspectionToolPresentation presentation) {
|
||||
public static OfflineProblemDescriptorNode create(@NotNull OfflineProblemDescriptor offlineDescriptor,
|
||||
@NotNull OfflineDescriptorResolveResult resolveResult,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
InspectionTreeModel model) {
|
||||
return new OfflineProblemDescriptorNode(resolveResult,
|
||||
presentation,
|
||||
offlineDescriptor);
|
||||
offlineDescriptor, model);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String calculatePresentableName() {
|
||||
String presentableName = super.calculatePresentableName();
|
||||
return presentableName.isEmpty() && getUserObject() instanceof OfflineProblemDescriptor
|
||||
? ProblemDescriptorUtil.unescapeTags(StringUtil.notNullize(((OfflineProblemDescriptor)getUserObject()).getDescription())).trim()
|
||||
return presentableName.isEmpty() && getDescriptor() == null
|
||||
? ProblemDescriptorUtil.unescapeTags(StringUtil.notNullize(myOfflineDescriptor.getDescription())).trim()
|
||||
: presentableName;
|
||||
}
|
||||
|
||||
|
||||
+1
-16
@@ -56,8 +56,7 @@ public class DefaultInspectionToolPresentation implements InspectionToolPresenta
|
||||
protected static final Logger LOG = Logger.getInstance(DefaultInspectionToolPresentation.class);
|
||||
|
||||
@NotNull private final InspectionToolWrapper myToolWrapper;
|
||||
@NotNull private final GlobalInspectionContextImpl myContext;
|
||||
protected InspectionNode myToolNode;
|
||||
@NotNull protected final GlobalInspectionContextImpl myContext;
|
||||
|
||||
private final SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> myProblemElements = createBidiMap();
|
||||
private final SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> mySuppressedElements = createBidiMap();
|
||||
@@ -255,11 +254,6 @@ public class DefaultInspectionToolPresentation implements InspectionToolPresenta
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionNode getToolNode() {
|
||||
return myToolNode;
|
||||
}
|
||||
|
||||
protected boolean isDisposed() {
|
||||
return isDisposed;
|
||||
}
|
||||
@@ -464,15 +458,6 @@ public class DefaultInspectionToolPresentation implements InspectionToolPresenta
|
||||
return myProblemElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createToolNode(@NotNull GlobalInspectionContextImpl globalInspectionContext, @NotNull InspectionNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity) {
|
||||
myToolNode = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IntentionAction findQuickFixes(@NotNull final CommonProblemDescriptor problemDescriptor, final String hint) {
|
||||
|
||||
@@ -4,20 +4,25 @@ package com.intellij.codeInspection.ui;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class InspectionGroupNode extends InspectionTreeNode {
|
||||
InspectionGroupNode(@NotNull String subGroup) {
|
||||
super(subGroup);
|
||||
private final String myGroup;
|
||||
|
||||
InspectionGroupNode(@NotNull String group, @NotNull InspectionTreeModel model) {
|
||||
super(model);
|
||||
myGroup = group;
|
||||
}
|
||||
|
||||
String getSubGroup() {
|
||||
return (String) getUserObject();
|
||||
return myGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appearsBold() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return myGroup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@ package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Icon;
|
||||
|
||||
public class InspectionModuleNode extends InspectionTreeNode{
|
||||
public class InspectionModuleNode extends InspectionTreeNode {
|
||||
@NotNull
|
||||
private final Module myModule;
|
||||
public InspectionModuleNode(final Module module) {
|
||||
super(module);
|
||||
|
||||
public InspectionModuleNode(@NotNull Module module, InspectionTreeModel model) {
|
||||
super(model);
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
@@ -32,11 +35,12 @@ public class InspectionModuleNode extends InspectionTreeNode{
|
||||
return myModule.isDisposed() ? null : ModuleType.get(myModule).getIcon();
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
public String getName() {
|
||||
return myModule.getName();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,24 +21,19 @@ import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class InspectionNode extends InspectionTreeNode {
|
||||
@NotNull private final InspectionToolWrapper myToolWrapper;
|
||||
@NotNull private final InspectionProfileImpl myProfile;
|
||||
|
||||
public InspectionNode(@NotNull InspectionToolWrapper toolWrapper, @NotNull InspectionProfileImpl profile) {
|
||||
super(toolWrapper);
|
||||
public InspectionNode(@NotNull InspectionToolWrapper toolWrapper, @NotNull InspectionProfileImpl profile, @NotNull InspectionTreeModel model) {
|
||||
super(model);
|
||||
myToolWrapper = toolWrapper;
|
||||
myProfile = profile;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getToolWrapper().getDisplayName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionToolWrapper getToolWrapper() {
|
||||
return (InspectionToolWrapper)getUserObject();
|
||||
return myToolWrapper;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -47,4 +42,9 @@ public class InspectionNode extends InspectionTreeNode {
|
||||
final String shortName = getToolWrapper().getShortName();
|
||||
return myProfile.getTools(shortName, null).isEnabled() ? null : "Disabled";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return getToolWrapper().getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,23 +18,27 @@ package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.util.PlatformIcons;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Icon;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class InspectionPackageNode extends InspectionTreeNode {
|
||||
private final String myPackageName;
|
||||
|
||||
public InspectionPackageNode(String packageName) {
|
||||
super(packageName);
|
||||
public InspectionPackageNode(String packageName, InspectionTreeModel model) {
|
||||
super(model);
|
||||
myPackageName = packageName;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return (String) getUserObject();
|
||||
return myPackageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean expanded) {
|
||||
return PlatformIcons.PACKAGE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return myPackageName;
|
||||
}
|
||||
}
|
||||
|
||||
+102
-290
@@ -14,7 +14,10 @@ import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.actions.ExportHTMLAction;
|
||||
import com.intellij.codeInspection.ui.actions.InvokeQuickFixAction;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.ide.*;
|
||||
import com.intellij.ide.CommonActionsManager;
|
||||
import com.intellij.ide.DefaultTreeExpander;
|
||||
import com.intellij.ide.OccurenceNavigator;
|
||||
import com.intellij.ide.TreeExpander;
|
||||
import com.intellij.ide.actions.exclusion.ExclusionHandler;
|
||||
import com.intellij.ide.util.PsiNavigationSupport;
|
||||
import com.intellij.injected.editor.VirtualFileWindow;
|
||||
@@ -23,7 +26,6 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
@@ -43,27 +45,25 @@ import com.intellij.profile.ProfileChangeAdapter;
|
||||
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.util.EditSourceOnDoubleClickHandler;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.OnePixelSplitter;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.SideBorder;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.OpenSourceUtil;
|
||||
import com.intellij.util.concurrency.SequentialTaskExecutor;
|
||||
import com.intellij.util.ui.EdtInvocationManager;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
@@ -77,8 +77,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
|
||||
@NotNull
|
||||
private final InspectionTree myTree;
|
||||
@NotNull
|
||||
private final OccurenceNavigator myOccurenceNavigator;
|
||||
private volatile InspectionProfileImpl myInspectionProfile;
|
||||
private final boolean mySettingsEnabled;
|
||||
@NotNull
|
||||
@@ -91,7 +89,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
private final GlobalInspectionContextImpl myGlobalInspectionContext;
|
||||
private boolean myRerun;
|
||||
private volatile boolean myDisposed;
|
||||
private int myUpdatingRequestors; //accessed only in edt
|
||||
private boolean myApplyingFix; //accessed only in edt
|
||||
|
||||
@NotNull
|
||||
@@ -100,11 +97,11 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
private final ExclusionHandler<InspectionTreeNode> myExclusionHandler;
|
||||
private EditorEx myPreviewEditor;
|
||||
private InspectionTreeLoadingProgressAware myLoadingProgressPreview;
|
||||
private final Alarm myLoadingProgressPreviewAlarm = new Alarm(this);
|
||||
private final InspectionViewSuppressActionHolder mySuppressActionHolder = new InspectionViewSuppressActionHolder();
|
||||
|
||||
private final Object myTreeStructureUpdateLock = new Object();
|
||||
private final ExecutorService myTreeUpdater = SequentialTaskExecutor
|
||||
.createSequentialApplicationPoolExecutor("Inspection-View-Tree-Updater");
|
||||
private final ExecutorService myTreeUpdater = SequentialTaskExecutor.createSequentialApplicationPoolExecutor("Inspection-View-Tree-Updater");
|
||||
private volatile boolean myUpdating;
|
||||
|
||||
public InspectionResultsView(@NotNull GlobalInspectionContextImpl globalInspectionContext,
|
||||
@NotNull InspectionRVContentProvider provider) {
|
||||
@@ -114,9 +111,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
myGlobalInspectionContext = globalInspectionContext;
|
||||
myProvider = provider;
|
||||
myTree = new InspectionTree(globalInspectionContext, this);
|
||||
initTreeListeners();
|
||||
|
||||
myOccurenceNavigator = initOccurenceNavigator();
|
||||
|
||||
mySplitter = new OnePixelSplitter(false, AnalysisUIOptions.getInstance(globalInspectionContext.getProject()).SPLITTER_PROPORTION);
|
||||
mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT));
|
||||
@@ -160,11 +154,9 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
public void onDone(boolean isExcludeAction) {
|
||||
if (isExcludeAction) {
|
||||
myTree.removeSelectedProblems();
|
||||
} else {
|
||||
myTree.repaint();
|
||||
}
|
||||
else {
|
||||
resetTree();
|
||||
}
|
||||
syncRightPanel();
|
||||
}
|
||||
};
|
||||
@@ -201,98 +193,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
});
|
||||
}
|
||||
|
||||
private void initTreeListeners() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return;
|
||||
}
|
||||
myTree.getSelectionModel().addTreeSelectionListener(e -> {
|
||||
if (myTree.isUnderQueueUpdate()) return;
|
||||
syncRightPanel();
|
||||
if (isAutoScrollMode()) {
|
||||
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(this), false);
|
||||
}
|
||||
});
|
||||
|
||||
EditSourceOnDoubleClickHandler.install(myTree);
|
||||
|
||||
myTree.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PopupHandler.installPopupHandler(myTree, IdeActions.INSPECTION_TOOL_WINDOW_TREE_POPUP, ActionPlaces.CODE_INSPECTION);
|
||||
SmartExpander.installOn(myTree);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private OccurenceNavigatorSupport initOccurenceNavigator() {
|
||||
return new OccurenceNavigatorSupport(myTree) {
|
||||
@Override
|
||||
protected boolean isOccurrenceNode(@NotNull DefaultMutableTreeNode node) {
|
||||
if (node instanceof InspectionTreeNode && ((InspectionTreeNode)node).isExcluded()) {
|
||||
return false;
|
||||
}
|
||||
if (node instanceof RefElementNode) {
|
||||
final RefElementNode refNode = (RefElementNode)node;
|
||||
if (refNode.hasDescriptorsUnder()) return false;
|
||||
final RefEntity element = refNode.getElement();
|
||||
return element != null && element.isValid();
|
||||
}
|
||||
return node instanceof ProblemDescriptionNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected Navigatable createDescriptorForNode(@NotNull DefaultMutableTreeNode node) {
|
||||
if (node instanceof InspectionTreeNode && ((InspectionTreeNode)node).isExcluded()) {
|
||||
return null;
|
||||
}
|
||||
if (node instanceof RefElementNode) {
|
||||
final RefElementNode refNode = (RefElementNode)node;
|
||||
if (refNode.hasDescriptorsUnder()) return null;
|
||||
final RefEntity element = refNode.getElement();
|
||||
if (element == null || !element.isValid()) return null;
|
||||
final CommonProblemDescriptor problem = refNode.getDescriptor();
|
||||
if (problem != null) {
|
||||
return navigate(problem);
|
||||
}
|
||||
if (element instanceof RefElement) {
|
||||
return getOpenFileDescriptor((RefElement)element);
|
||||
}
|
||||
}
|
||||
else if (node instanceof ProblemDescriptionNode) {
|
||||
ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node;
|
||||
boolean isValid = problemNode.isValid() && (!problemNode.isQuickFixAppliedFromView() ||
|
||||
problemNode.calculateIsValid());
|
||||
return isValid
|
||||
? navigate(problemNode.getDescriptor())
|
||||
: InspectionResultsViewUtil.getNavigatableForInvalidNode(problemNode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Navigatable navigate(final CommonProblemDescriptor descriptor) {
|
||||
return getSelectedNavigatable(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getNextOccurenceActionName() {
|
||||
return InspectionsBundle.message("inspection.action.go.next");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPreviousOccurenceActionName() {
|
||||
return InspectionsBundle.message("inspection.action.go.prev");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void createActionsToolbar() {
|
||||
JPanel westPanel = JBUI.Panels.simplePanel()
|
||||
@@ -319,8 +219,8 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
final TreeExpander treeExpander = new DefaultTreeExpander(myTree);
|
||||
group.add(actionsManager.createExpandAllAction(treeExpander, myTree));
|
||||
group.add(actionsManager.createCollapseAllAction(treeExpander, myTree));
|
||||
group.add(actionsManager.createPrevOccurenceAction(myOccurenceNavigator));
|
||||
group.add(actionsManager.createNextOccurenceAction(myOccurenceNavigator));
|
||||
group.add(actionsManager.createPrevOccurenceAction(myTree.getOccurenceNavigator()));
|
||||
group.add(actionsManager.createNextOccurenceAction(myTree.getOccurenceNavigator()));
|
||||
group.add(ActionManager.getInstance().getAction("EditInspectionSettings"));
|
||||
|
||||
return createToolbar(group);
|
||||
@@ -328,34 +228,34 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
|
||||
@Override
|
||||
public boolean hasNextOccurence() {
|
||||
return myOccurenceNavigator.hasNextOccurence();
|
||||
return myTree.getOccurenceNavigator().hasNextOccurence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPreviousOccurence() {
|
||||
return myOccurenceNavigator.hasPreviousOccurence();
|
||||
return myTree.getOccurenceNavigator().hasPreviousOccurence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OccurenceInfo goNextOccurence() {
|
||||
return myOccurenceNavigator.goNextOccurence();
|
||||
return myTree.getOccurenceNavigator().goNextOccurence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OccurenceInfo goPreviousOccurence() {
|
||||
return myOccurenceNavigator.goPreviousOccurence();
|
||||
return myTree.getOccurenceNavigator().goPreviousOccurence();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getNextOccurenceActionName() {
|
||||
return myOccurenceNavigator.getNextOccurenceActionName();
|
||||
return myTree.getOccurenceNavigator().getNextOccurenceActionName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPreviousOccurenceActionName() {
|
||||
return myOccurenceNavigator.getPreviousOccurenceActionName();
|
||||
return myTree.getOccurenceNavigator().getPreviousOccurenceActionName();
|
||||
}
|
||||
|
||||
private static JComponent createToolbar(final DefaultActionGroup specialGroup) {
|
||||
@@ -376,39 +276,17 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAutoScrollMode() {
|
||||
boolean isAutoScrollMode() {
|
||||
String activeToolWindowId = ToolWindowManager.getInstance(getProject()).getActiveToolWindowId();
|
||||
return myGlobalInspectionContext.getUIOptions().AUTOSCROLL_TO_SOURCE &&
|
||||
(activeToolWindowId == null || activeToolWindowId.equals(ToolWindowId.INSPECTION));
|
||||
}
|
||||
|
||||
Object getTreeStructureUpdateLock() {
|
||||
return myTreeStructureUpdateLock;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Navigatable getOpenFileDescriptor(final RefElement refElement) {
|
||||
PsiElement psiElement = refElement.getPsiElement();
|
||||
if (psiElement == null) return null;
|
||||
final PsiFile containingFile = psiElement.getContainingFile();
|
||||
if (containingFile == null) return null;
|
||||
VirtualFile file = containingFile.getVirtualFile();
|
||||
if (file == null) return null;
|
||||
return PsiNavigationSupport.getInstance().createNavigatable(refElement.getRefManager().getProject(), file,
|
||||
psiElement.getTextOffset());
|
||||
}
|
||||
|
||||
public void setApplyingFix(boolean applyingFix) {
|
||||
myApplyingFix = applyingFix;
|
||||
syncRightPanel();
|
||||
}
|
||||
|
||||
void openRightPanelIfNeed() {
|
||||
if (mySplitter.getSecondComponent() == null) {
|
||||
syncRightPanel();
|
||||
}
|
||||
}
|
||||
|
||||
public void syncRightPanel() {
|
||||
final Editor oldEditor = myPreviewEditor;
|
||||
try {
|
||||
@@ -482,7 +360,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
editorPanel.setLayout(new BorderLayout());
|
||||
final JPanel actionsPanel = new JPanel(new BorderLayout());
|
||||
editorPanel.add(actionsPanel, BorderLayout.NORTH);
|
||||
final int problemCount = myTree.getSelectedProblemCount(true);
|
||||
final int problemCount = myTree.getSelectedProblemCount();
|
||||
JComponent previewPanel = null;
|
||||
final InspectionToolWrapper tool = myTree.getSelectedToolWrapper(true);
|
||||
if (tool != null) {
|
||||
@@ -597,12 +475,15 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
HighlightDisplayLevel errorLevel,
|
||||
boolean groupedBySeverity,
|
||||
boolean isSingleInspectionRun) {
|
||||
InspectionTreeNode parentNode = myTree.getToolParentNode(toolWrapper, errorLevel, groupedBySeverity, isSingleInspectionRun);
|
||||
InspectionNode toolNode = new InspectionNode(toolWrapper, myInspectionProfile);
|
||||
boolean showStructure = myGlobalInspectionContext.getUIOptions().SHOW_STRUCTURE;
|
||||
toolNode = myProvider.appendToolNodeContent(myGlobalInspectionContext, toolNode, parentNode, showStructure, groupedBySeverity);
|
||||
InspectionTreeNode toolNode = myTree.getToolProblemsRootNode(toolWrapper, errorLevel, groupedBySeverity, isSingleInspectionRun);
|
||||
myProvider.appendToolNodeContent(myGlobalInspectionContext,
|
||||
toolWrapper,
|
||||
toolNode,
|
||||
myGlobalInspectionContext.getUIOptions().SHOW_STRUCTURE,
|
||||
groupedBySeverity);
|
||||
InspectionToolPresentation presentation = myGlobalInspectionContext.getPresentation(toolWrapper);
|
||||
presentation.createToolNode(myGlobalInspectionContext, toolNode, myProvider, parentNode, showStructure, groupedBySeverity);
|
||||
presentation.patchToolNode(toolNode, myProvider,
|
||||
myGlobalInspectionContext.getUIOptions().SHOW_STRUCTURE, groupedBySeverity);
|
||||
registerActionShortcuts(presentation);
|
||||
}
|
||||
|
||||
@@ -628,39 +509,38 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
}
|
||||
|
||||
void addProblemDescriptors(InspectionToolWrapper wrapper, RefEntity refElement, CommonProblemDescriptor[] descriptors) {
|
||||
updateTree(() -> {
|
||||
synchronized (myTreeStructureUpdateLock) {
|
||||
ReadAction.run(() -> {
|
||||
if (!isDisposed()) {
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed();
|
||||
final AnalysisUIOptions uiOptions = myGlobalInspectionContext.getUIOptions();
|
||||
final InspectionToolPresentation presentation = myGlobalInspectionContext.getPresentation(wrapper);
|
||||
if (presentation.getToolNode() == null) {
|
||||
presentation.updateContent();
|
||||
addTool(wrapper, HighlightDisplayLevel.find(presentation.getSeverity((RefElement)refElement)),
|
||||
uiOptions.GROUP_BY_SEVERITY, isSingleInspectionRun());
|
||||
return;
|
||||
}
|
||||
final InspectionNode toolNode = presentation.getToolNode();
|
||||
LOG.assertTrue(toolNode != null);
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<>(1);
|
||||
problems.put(refElement, descriptors);
|
||||
final Map<String, Set<RefEntity>> contents = new HashMap<>();
|
||||
final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement);
|
||||
Set<RefEntity> content = contents.computeIfAbsent(groupName, __ -> new HashSet<>());
|
||||
content.add(refElement);
|
||||
updateTree(() -> ReadAction.run(() -> {
|
||||
if (!isDisposed()) {
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed();
|
||||
final AnalysisUIOptions uiOptions = myGlobalInspectionContext.getUIOptions();
|
||||
final InspectionToolPresentation presentation = myGlobalInspectionContext.getPresentation(wrapper);
|
||||
|
||||
getProvider().appendToolNodeContent(myGlobalInspectionContext,
|
||||
toolNode,
|
||||
(InspectionTreeNode)toolNode.getParent(),
|
||||
uiOptions.SHOW_STRUCTURE,
|
||||
true,
|
||||
contents,
|
||||
problems::get);
|
||||
final InspectionTreeNode toolNode =
|
||||
myTree.getToolProblemsRootNode(wrapper, HighlightDisplayLevel.find(presentation.getSeverity((RefElement)refElement)),
|
||||
uiOptions.GROUP_BY_SEVERITY, isSingleInspectionRun());
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<>(1);
|
||||
problems.put(refElement, descriptors);
|
||||
final Map<String, Set<RefEntity>> contents = new HashMap<>();
|
||||
final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement);
|
||||
Set<RefEntity> content = contents.computeIfAbsent(groupName, __ -> new HashSet<>());
|
||||
content.add(refElement);
|
||||
|
||||
getProvider().appendToolNodeContent(myGlobalInspectionContext,
|
||||
wrapper,
|
||||
toolNode,
|
||||
uiOptions.SHOW_STRUCTURE,
|
||||
true,
|
||||
contents,
|
||||
problems::get);
|
||||
|
||||
myLoadingProgressPreviewAlarm.cancelAllRequests();
|
||||
myLoadingProgressPreviewAlarm.addRequest(() -> {
|
||||
if (myLoadingProgressPreview != null) {
|
||||
myLoadingProgressPreview.updateLoadingProgress();
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
@@ -670,14 +550,11 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
final Runnable buildAction = () -> {
|
||||
try {
|
||||
setUpdating(true);
|
||||
synchronized (myTreeStructureUpdateLock) {
|
||||
myTree.removeAllNodes();
|
||||
addToolsSynchronously(tools);
|
||||
}
|
||||
myTree.removeAllNodes();
|
||||
addToolsSynchronously(tools);
|
||||
}
|
||||
finally {
|
||||
setUpdating(false);
|
||||
UIUtil.invokeLaterIfNeeded(() -> myTree.restoreExpansionAndSelection(false));
|
||||
}
|
||||
};
|
||||
if (app.isUnitTestMode()) {
|
||||
@@ -688,35 +565,16 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
}
|
||||
|
||||
public void setUpdating(boolean isUpdating) {
|
||||
final Runnable update = () -> {
|
||||
if (isUpdating) {
|
||||
myUpdatingRequestors++;
|
||||
} else {
|
||||
myUpdatingRequestors--;
|
||||
}
|
||||
boolean hasUpdatingRequestors = myUpdatingRequestors > 0;
|
||||
myTree.setPaintBusy(hasUpdatingRequestors);
|
||||
if (!hasUpdatingRequestors && myLoadingProgressPreview != null) {
|
||||
myLoadingProgressPreview.treeLoaded();
|
||||
}
|
||||
//TODO Dmitrii Batkovich it's a hack (preview panel should be created during selection update)
|
||||
if (!hasUpdatingRequestors && mySplitter.getSecondComponent() == null) {
|
||||
final int count = myTree.getRoot().getChildCount();
|
||||
if (count != 0) {
|
||||
if (myTree.getSelectionCount() == 0) {
|
||||
TreeUtil.selectFirstNode(myTree);
|
||||
}
|
||||
syncRightPanel();
|
||||
myUpdating = isUpdating;
|
||||
if (!isUpdating) {
|
||||
myLoadingProgressPreviewAlarm.cancelAllRequests();
|
||||
myLoadingProgressPreviewAlarm.addRequest(() -> {
|
||||
if (myLoadingProgressPreview != null) {
|
||||
myLoadingProgressPreview.treeLoaded();
|
||||
}
|
||||
}
|
||||
};
|
||||
final Application app = ApplicationManager.getApplication();
|
||||
if (app.isDispatchThread()) {
|
||||
update.run();
|
||||
}
|
||||
else {
|
||||
app.invokeLater(update, ModalityState.any());
|
||||
}, 200);
|
||||
}
|
||||
EdtInvocationManager.getInstance().invokeLater(() -> myTree.setPaintBusy(myUpdating));
|
||||
}
|
||||
|
||||
public void addTools(Collection<? extends Tools> tools) {
|
||||
@@ -725,30 +583,23 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
|
||||
private void addToolsSynchronously(Collection<? extends Tools> tools) {
|
||||
if (isDisposed()) return;
|
||||
synchronized (myTreeStructureUpdateLock) {
|
||||
InspectionProfileImpl profile = myInspectionProfile;
|
||||
boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY;
|
||||
boolean singleInspectionRun = isSingleInspectionRun();
|
||||
for (Tools currentTools : tools) {
|
||||
InspectionToolWrapper defaultToolWrapper = currentTools.getDefaultState().getTool();
|
||||
final HighlightDisplayKey key = HighlightDisplayKey.find(defaultToolWrapper.getShortName());
|
||||
for (ScopeToolState state : myProvider.getTools(currentTools)) {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
if (ReadAction.compute(() -> myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper))) {
|
||||
addTool(toolWrapper,
|
||||
profile.getErrorLevel(key, state.getScope(getProject()), getProject()),
|
||||
isGroupedBySeverity,
|
||||
singleInspectionRun);
|
||||
}
|
||||
InspectionProfileImpl profile = myInspectionProfile;
|
||||
boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY;
|
||||
boolean singleInspectionRun = isSingleInspectionRun();
|
||||
for (Tools currentTools : tools) {
|
||||
InspectionToolWrapper defaultToolWrapper = currentTools.getDefaultState().getTool();
|
||||
final HighlightDisplayKey key = HighlightDisplayKey.find(defaultToolWrapper.getShortName());
|
||||
for (ScopeToolState state : myProvider.getTools(currentTools)) {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
if (ReadAction.compute(() -> myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper))) {
|
||||
addTool(toolWrapper,
|
||||
profile.getErrorLevel(key, state.getScope(getProject()), getProject()),
|
||||
isGroupedBySeverity,
|
||||
singleInspectionRun);
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
if (myTree.getSelectionCount() == 0) {
|
||||
TreeUtil.selectFirstNode(myTree);
|
||||
}
|
||||
syncRightPanel();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -761,12 +612,22 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
if (PlatformDataKeys.HELP_ID.is(dataId)) return HELP_ID;
|
||||
if (DATA_KEY.is(dataId)) return this;
|
||||
if (ExclusionHandler.EXCLUSION_HANDLER.is(dataId)) return myExclusionHandler;
|
||||
if (!ApplicationManager.getApplication().isDispatchThread()) return null;
|
||||
TreePath[] paths = myTree.getSelectionPaths();
|
||||
if (paths == null || paths.length == 0) return null;
|
||||
|
||||
if (paths.length > 1) {
|
||||
if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
|
||||
return collectPsiElements();
|
||||
RefEntity[] refElements = myTree.getSelectedElements();
|
||||
List<PsiElement> psiElements = new ArrayList<>();
|
||||
for (RefEntity refElement : refElements) {
|
||||
PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getPsiElement() : null;
|
||||
if (psiElement != null && psiElement.isValid()) {
|
||||
psiElements.add(psiElement);
|
||||
}
|
||||
}
|
||||
|
||||
return PsiUtilCore.toPsiElementArray(psiElements);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -789,25 +650,11 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
PsiElement psiElement = item instanceof RefElement ? ((RefElement)item).getPsiElement() : null;
|
||||
if (psiElement == null) return null;
|
||||
|
||||
final CommonProblemDescriptor problem = refElementNode.getDescriptor();
|
||||
if (problem instanceof ProblemDescriptor) {
|
||||
PsiElement elementFromDescriptor = ((ProblemDescriptor)problem).getPsiElement();
|
||||
if (elementFromDescriptor == null && CommonDataKeys.NAVIGATABLE.is(dataId) && refElementNode.getChildCount() != 0) {
|
||||
final InspectionTreeNode node = (InspectionTreeNode)refElementNode.getChildAt(0);
|
||||
if (node.isValid()) {
|
||||
return InspectionResultsViewUtil.getNavigatableForInvalidNode((ProblemDescriptionNode)node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
psiElement = elementFromDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
if (CommonDataKeys.NAVIGATABLE.is(dataId)) {
|
||||
return getSelectedNavigatable(problem, psiElement);
|
||||
return getSelectedNavigatable(null, psiElement);
|
||||
}
|
||||
else if (CommonDataKeys.PSI_ELEMENT.is(dataId)) {
|
||||
return psiElement != null && psiElement.isValid() ? psiElement : null;
|
||||
return psiElement.isValid() ? psiElement : null;
|
||||
}
|
||||
}
|
||||
else if (selectedNode instanceof ProblemDescriptionNode && CommonDataKeys.NAVIGATABLE.is(dataId)) {
|
||||
@@ -818,28 +665,14 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
return null;
|
||||
}
|
||||
|
||||
void resetTree() {
|
||||
try {
|
||||
myTree.setQueueUpdate(true);
|
||||
final TreePath[] selectionPath = myTree.getSelectionPaths();
|
||||
final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myTree);
|
||||
((DefaultTreeModel)myTree.getModel()).reload();
|
||||
TreeUtil.restoreExpandedPaths(myTree, expandedPaths);
|
||||
myTree.setSelectionPaths(selectionPath);
|
||||
}
|
||||
finally {
|
||||
myTree.setQueueUpdate(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Navigatable getSelectedNavigatable(final CommonProblemDescriptor descriptor) {
|
||||
public static Navigatable getSelectedNavigatable(final CommonProblemDescriptor descriptor) {
|
||||
return getSelectedNavigatable(descriptor,
|
||||
descriptor instanceof ProblemDescriptor ? ((ProblemDescriptor)descriptor).getPsiElement() : null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Navigatable getSelectedNavigatable(final CommonProblemDescriptor descriptor, final PsiElement psiElement) {
|
||||
private static Navigatable getSelectedNavigatable(CommonProblemDescriptor descriptor, PsiElement psiElement) {
|
||||
if (descriptor instanceof ProblemDescriptorBase) {
|
||||
Navigatable navigatable = ((ProblemDescriptorBase)descriptor).getNavigatable();
|
||||
if (navigatable != null) {
|
||||
@@ -861,25 +694,11 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
startOffset = textRange.getStartOffset();
|
||||
}
|
||||
}
|
||||
return PsiNavigationSupport.getInstance().createNavigatable(getProject(), virtualFile, startOffset);
|
||||
return PsiNavigationSupport.getInstance().createNavigatable(psiElement.getProject(), virtualFile, startOffset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiElement[] collectPsiElements() {
|
||||
RefEntity[] refElements = myTree.getSelectedElements();
|
||||
List<PsiElement> psiElements = new ArrayList<>();
|
||||
for (RefEntity refElement : refElements) {
|
||||
PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getPsiElement() : null;
|
||||
if (psiElement != null && psiElement.isValid()) {
|
||||
psiElements.add(psiElement);
|
||||
}
|
||||
}
|
||||
|
||||
return PsiUtilCore.toPsiElementArray(psiElements);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionTree getTree() {
|
||||
return myTree;
|
||||
@@ -929,13 +748,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
}
|
||||
|
||||
public boolean isUpdating() {
|
||||
return myUpdatingRequestors > 0;
|
||||
}
|
||||
|
||||
void updateRightPanelLoading() {
|
||||
if (!myDisposed && isUpdating() && myLoadingProgressPreview != null) {
|
||||
myLoadingProgressPreview.updateLoadingProgress();
|
||||
}
|
||||
return myUpdating;
|
||||
}
|
||||
|
||||
public boolean hasProblems() {
|
||||
@@ -968,7 +781,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
myRerun = true;
|
||||
if (myScope.isValid()) {
|
||||
AnalysisUIOptions.getInstance(getProject()).save(myGlobalInspectionContext.getUIOptions());
|
||||
myGlobalInspectionContext.setTreeState(getTree().getTreeState());
|
||||
myGlobalInspectionContext.doInspections(myScope);
|
||||
} else {
|
||||
GlobalInspectionContextImpl.NOTIFICATION_GROUP.createNotification(InspectionsBundle.message("inspection.view.invalid.scope.message"), NotificationType.INFORMATION).notify(getProject());
|
||||
|
||||
+2
-9
@@ -2,7 +2,6 @@
|
||||
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
@@ -26,6 +25,8 @@ import java.util.Comparator;
|
||||
public class InspectionResultsViewComparator implements Comparator<InspectionTreeNode> {
|
||||
private static final Logger LOG = Logger.getInstance(InspectionResultsViewComparator.class);
|
||||
|
||||
public static final InspectionResultsViewComparator INSTANCE = new InspectionResultsViewComparator();
|
||||
|
||||
public boolean areEqual(InspectionTreeNode o1, InspectionTreeNode o2) {
|
||||
return o1.getClass().equals(o2.getClass()) && compare(o1, o2) == 0;
|
||||
}
|
||||
@@ -192,12 +193,4 @@ public class InspectionResultsViewComparator implements Comparator<InspectionTre
|
||||
}
|
||||
return entity1.getQualifiedName().compareToIgnoreCase(entity2.getQualifiedName());
|
||||
}
|
||||
|
||||
private static class InspectionResultsViewComparatorHolder {
|
||||
private static final InspectionResultsViewComparator ourInstance = new InspectionResultsViewComparator();
|
||||
}
|
||||
|
||||
public static InspectionResultsViewComparator getInstance() {
|
||||
return InspectionResultsViewComparatorHolder.ourInstance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,13 @@
|
||||
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class InspectionRootNode extends InspectionTreeNode {
|
||||
public InspectionRootNode(Project project, @NotNull InspectionTreeUpdater updater) {
|
||||
super(project);
|
||||
myUpdater = updater;
|
||||
protected InspectionRootNode(InspectionTreeModel model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
public InspectionTreeUpdater getUpdater() {
|
||||
return myUpdater;
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return "InspectionViewTree";
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -5,18 +5,20 @@ package com.intellij.codeInspection.ui;
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Icon;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class InspectionSeverityGroupNode extends InspectionTreeNode{
|
||||
|
||||
private final HighlightDisplayLevel myLevel;
|
||||
private final SeverityRegistrar mySeverityRegistrar;
|
||||
|
||||
public InspectionSeverityGroupNode(final SeverityRegistrar severityRegistrar, final HighlightDisplayLevel level) {
|
||||
super(level);
|
||||
public InspectionSeverityGroupNode(@NotNull SeverityRegistrar severityRegistrar,
|
||||
@NotNull HighlightDisplayLevel level,
|
||||
@NotNull InspectionTreeModel model) {
|
||||
super(model);
|
||||
myLevel = level;
|
||||
mySeverityRegistrar = severityRegistrar;
|
||||
}
|
||||
@@ -31,8 +33,9 @@ public class InspectionSeverityGroupNode extends InspectionTreeNode{
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return StringUtil.capitalize(myLevel.toString().toLowerCase());
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return StringUtil.capitalize(myLevel.toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public HighlightDisplayLevel getSeverityLevel() {
|
||||
|
||||
+9
-12
@@ -33,19 +33,16 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
@NotNull
|
||||
InspectionToolWrapper getToolWrapper();
|
||||
|
||||
void createToolNode(@NotNull GlobalInspectionContextImpl globalInspectionContext,
|
||||
@NotNull InspectionNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity);
|
||||
default void patchToolNode(@NotNull InspectionTreeNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity) {
|
||||
|
||||
@Nullable
|
||||
InspectionNode getToolNode();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default RefElementNode createRefNode(@Nullable RefEntity entity) {
|
||||
return new RefElementNode(entity, this);
|
||||
default RefElementNode createRefNode(@Nullable RefEntity entity, @NotNull InspectionTreeModel model) {
|
||||
return new RefElementNode(entity, this, model);
|
||||
}
|
||||
|
||||
void updateContent();
|
||||
@@ -127,8 +124,8 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
return false;
|
||||
}
|
||||
|
||||
default int getProblemsCount(@NotNull InspectionTree tree) {
|
||||
return tree.getSelectedDescriptors().length;
|
||||
default boolean showProblemCount() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -4,42 +4,54 @@ package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.ex.BatchModeDescriptorsUtil;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.util.SynchronizedBidiMultiMap;
|
||||
import com.intellij.concurrency.ConcurrentCollectionFactory;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.OccurenceNavigator;
|
||||
import com.intellij.ide.util.PsiNavigationSupport;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionsConfigTreeComparator;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.SmartPsiElementPointer;
|
||||
import com.intellij.ui.PopupHandler;
|
||||
import com.intellij.ui.SmartExpander;
|
||||
import com.intellij.ui.TreeSpeedSearch;
|
||||
import com.intellij.ui.tree.AsyncTreeModel;
|
||||
import com.intellij.ui.tree.TreePathUtil;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.EditSourceOnDoubleClickHandler;
|
||||
import com.intellij.util.OpenSourceUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.intellij.util.containers.TreeTraversal;
|
||||
import com.intellij.util.ui.EdtInvocationManager;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeModelAdapter;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeWillExpandListener;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.event.TreeModelEvent;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.intellij.codeInspection.CommonProblemDescriptor.DESCRIPTOR_COMPARATOR;
|
||||
@@ -48,37 +60,79 @@ public class InspectionTree extends Tree {
|
||||
private static final Logger LOG = Logger.getInstance(InspectionTree.class);
|
||||
|
||||
@NotNull private final GlobalInspectionContextImpl myContext;
|
||||
@NotNull private final ConcurrentMap<HighlightDisplayLevel, InspectionSeverityGroupNode> mySeverityGroupNodes = ContainerUtil.newConcurrentMap();
|
||||
@NotNull private final ConcurrentMap<HighlightDisplayLevel, ConcurrentMap<String[], InspectionGroupNode>> myGroups = ContainerUtil.newConcurrentMap();
|
||||
private final InspectionTreeModel myModel;
|
||||
|
||||
@NotNull private InspectionTreeState myState = new InspectionTreeState();
|
||||
private boolean myQueueUpdate;
|
||||
private final OccurenceNavigator myOccurenceNavigator = new MyOccurrenceNavigator();
|
||||
|
||||
public InspectionTree(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionResultsView view) {
|
||||
Project project = context.getProject();
|
||||
setModel(new DefaultTreeModel(new InspectionRootNode(project, new InspectionTreeUpdater(view))));
|
||||
myModel = new InspectionTreeModel();
|
||||
setModel(new AsyncTreeModel(myModel, view));
|
||||
myContext = context;
|
||||
|
||||
setCellRenderer(new InspectionTreeCellRenderer(view));
|
||||
setRootVisible(false);
|
||||
setShowsRootHandles(true);
|
||||
UIUtil.setLineStyleAngled(this);
|
||||
addTreeWillExpandListener(new ExpandListener());
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
getSelectionModel().addTreeSelectionListener(e -> {
|
||||
if (isUnderQueueUpdate()) return;
|
||||
InspectionResultsView view1 = getContext().getView();
|
||||
if (view1 != null && !view1.isDisposed()) {
|
||||
view1.syncRightPanel();
|
||||
if (view1.isAutoScrollMode()) {
|
||||
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(this), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myState.getExpandedUserObjects().add(project);
|
||||
EditSourceOnDoubleClickHandler.install(this);
|
||||
|
||||
TreeUtil.installActions(this);
|
||||
new TreeSpeedSearch(this, o -> InspectionsConfigTreeComparator.getDisplayTextToSort(o.getLastPathComponent().toString()));
|
||||
addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
InspectionResultsView view1 = getContext().getView();
|
||||
if (view1 != null && !view1.isDisposed()) {
|
||||
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(view1), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
TreeUtil.installActions(this);
|
||||
PopupHandler.installPopupHandler(this, IdeActions.INSPECTION_TOOL_WINDOW_TREE_POPUP, ActionPlaces.CODE_INSPECTION);
|
||||
new TreeSpeedSearch(this, o -> InspectionsConfigTreeComparator.getDisplayTextToSort(o.getLastPathComponent().toString()));
|
||||
}
|
||||
|
||||
addTreeSelectionListener(e -> {
|
||||
TreePath newSelection = e.getNewLeadSelectionPath();
|
||||
if (newSelection != null && !isUnderQueueUpdate()) {
|
||||
myState.setSelectionPath(newSelection);
|
||||
getModel().addTreeModelListener(new TreeModelAdapter() {
|
||||
//TODO the same as DiscoveredTestTree (see setRootVisible)
|
||||
boolean myAlreadyDone;
|
||||
@Override
|
||||
protected void process(@NotNull TreeModelEvent event, @NotNull EventType type) {
|
||||
if (!myAlreadyDone && getSelectionCount() == 0) {
|
||||
myAlreadyDone = true;
|
||||
EdtInvocationManager.getInstance().invokeLater(() -> {
|
||||
expandPath(new TreePath(myModel.getRoot()));
|
||||
SmartExpander.installOn(InspectionTree.this);
|
||||
InspectionResultsView v = getContext().getView();
|
||||
if (v != null && !v.isDisposed()) {
|
||||
v.syncRightPanel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public InspectionTreeNode getRoot() {
|
||||
return myModel.getRoot();
|
||||
}
|
||||
|
||||
public InspectionTreeModel getInspectionTreeModel() {
|
||||
return myModel;
|
||||
}
|
||||
|
||||
public void setQueueUpdate(boolean queueUpdate) {
|
||||
myQueueUpdate = queueUpdate;
|
||||
}
|
||||
@@ -88,19 +142,7 @@ public class InspectionTree extends Tree {
|
||||
}
|
||||
|
||||
public void removeAllNodes() {
|
||||
mySeverityGroupNodes.clear();
|
||||
myGroups.clear();
|
||||
getRoot().removeAllChildren();
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
InspectionResultsView view = myContext.getView();
|
||||
if (view != null && !view.isDisposed()) {
|
||||
nodeStructureChanged(getRoot());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public InspectionTreeNode getRoot() {
|
||||
return (InspectionTreeNode)getModel().getRoot();
|
||||
myModel.clearTree();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -119,8 +161,17 @@ public class InspectionTree extends Tree {
|
||||
@Nullable
|
||||
public InspectionToolWrapper getSelectedToolWrapper(boolean allowDummy) {
|
||||
final TreePath[] paths = getSelectionPaths();
|
||||
if (paths == null) return null;
|
||||
InspectionToolWrapper toolWrapper = null;
|
||||
if (paths == null) {
|
||||
InspectionProfileImpl profile = myContext.getView().getCurrentProfile();
|
||||
String singleToolName = profile.getSingleTool();
|
||||
if (singleToolName != null) {
|
||||
InspectionToolWrapper tool = profile.getInspectionTool(singleToolName, myContext.getProject());
|
||||
LOG.assertTrue(tool != null);
|
||||
return tool;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
InspectionToolWrapper resultWrapper = null;
|
||||
for (TreePath path : paths) {
|
||||
Object[] nodes = path.getPath();
|
||||
for (int j = nodes.length - 1; j >= 0; j--) {
|
||||
@@ -128,23 +179,25 @@ public class InspectionTree extends Tree {
|
||||
if (node instanceof InspectionGroupNode) {
|
||||
return null;
|
||||
}
|
||||
InspectionToolWrapper wrapper = null;
|
||||
if (node instanceof InspectionNode) {
|
||||
InspectionToolWrapper wrapper = ((InspectionNode)node).getToolWrapper();
|
||||
if (!allowDummy && getContext().getPresentation(wrapper).isDummy()) {
|
||||
continue;
|
||||
}
|
||||
if (toolWrapper == null) {
|
||||
toolWrapper = wrapper;
|
||||
}
|
||||
else if (toolWrapper != wrapper) {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
wrapper = ((InspectionNode)node).getToolWrapper();
|
||||
} else if (node instanceof SuppressableInspectionTreeNode) {
|
||||
wrapper = ((SuppressableInspectionTreeNode)node).getPresentation().getToolWrapper();
|
||||
}
|
||||
if (wrapper == null || !allowDummy && getContext().getPresentation(wrapper).isDummy()) {
|
||||
continue;
|
||||
}
|
||||
if (resultWrapper == null) {
|
||||
resultWrapper = wrapper;
|
||||
}
|
||||
else if (resultWrapper != wrapper) {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return toolWrapper;
|
||||
return resultWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,6 +256,15 @@ public class InspectionTree extends Tree {
|
||||
return RefEntity.EMPTY_ELEMENTS_ARRAY;
|
||||
}
|
||||
|
||||
public OccurenceNavigator getOccurenceNavigator() {
|
||||
return myOccurenceNavigator;
|
||||
}
|
||||
|
||||
public void selectNode(InspectionTreeNode node) {
|
||||
TreePath path = getPathFor(node);
|
||||
TreeUtil.selectPath(this, path);
|
||||
}
|
||||
|
||||
private static void addElementsInNode(InspectionTreeNode node, Set<? super RefEntity> out) {
|
||||
if (!node.isValid()) return;
|
||||
if (node instanceof RefElementNode) {
|
||||
@@ -213,45 +275,44 @@ public class InspectionTree extends Tree {
|
||||
final RefEntity element = ((ProblemDescriptionNode)node).getElement();
|
||||
out.add(element);
|
||||
}
|
||||
final Enumeration children = node.children();
|
||||
while (children.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)children.nextElement();
|
||||
|
||||
for (InspectionTreeNode child : node.getChildren()) {
|
||||
addElementsInNode(child, out);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CommonProblemDescriptor[] getAllValidSelectedDescriptors() {
|
||||
return BatchModeDescriptorsUtil.flattenDescriptors(getSelectedDescriptorPacks(false, null, true));
|
||||
return BatchModeDescriptorsUtil.flattenDescriptors(getSelectedDescriptorPacks(false, null, true, null));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CommonProblemDescriptor[] getSelectedDescriptors() {
|
||||
return BatchModeDescriptorsUtil.flattenDescriptors(getSelectedDescriptorPacks(false, null, false));
|
||||
return BatchModeDescriptorsUtil.flattenDescriptors(getSelectedDescriptorPacks(false, null, false, null));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<CommonProblemDescriptor[]> getSelectedDescriptorPacks(boolean sortedByPosition,
|
||||
@Nullable Set<? super VirtualFile> readOnlyFilesSink,
|
||||
boolean allowResolved) {
|
||||
final TreePath[] paths = getSelectionPaths();
|
||||
boolean allowResolved,
|
||||
TreePath[] paths) {
|
||||
if (paths == null) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
paths = getSelectionPaths();
|
||||
}
|
||||
if (paths == null) return Collections.emptyList();
|
||||
|
||||
// key can be node or VirtualFile (if problem descriptor node parent is a file/member RefElementNode).
|
||||
MultiMap<Object, CommonProblemDescriptor> parentToChildNode = new MultiMap<>();
|
||||
TreeUtil
|
||||
.treePathTraverser(this)
|
||||
.withRoots(Arrays.asList(paths))
|
||||
.traverse()
|
||||
.map(p -> p.getLastPathComponent())
|
||||
//TODO expected thread
|
||||
TreeTraversal.PLAIN_BFS.traversal(
|
||||
ContainerUtil.map(paths, p -> (InspectionTreeNode)p.getLastPathComponent()),
|
||||
(InspectionTreeNode n) -> myModel.getChildren(n))
|
||||
.filter(ProblemDescriptionNode.class)
|
||||
.filter(node -> node.getDescriptor() != null && isNodeValidAndIncluded(node, allowResolved))
|
||||
.consumeEach(node -> {
|
||||
Object key = getVirtualFileOrEntity(node.getElement());
|
||||
parentToChildNode.putValue(key, node.getDescriptor());
|
||||
});
|
||||
|
||||
|
||||
final List<CommonProblemDescriptor[]> descriptors = new ArrayList<>();
|
||||
for (Map.Entry<Object, Collection<CommonProblemDescriptor>> entry : parentToChildNode.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
@@ -268,68 +329,53 @@ public class InspectionTree extends Tree {
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
InspectionTreeNode getToolParentNode(@NotNull InspectionToolWrapper toolWrapper,
|
||||
HighlightDisplayLevel errorLevel,
|
||||
boolean groupedBySeverity,
|
||||
boolean isSingleInspectionRun) {
|
||||
//synchronize
|
||||
if (!groupedBySeverity && isSingleInspectionRun) {
|
||||
return getRoot();
|
||||
}
|
||||
String[] groupPath = toolWrapper.getGroupPath();
|
||||
if (groupPath.length == 0) {
|
||||
LOG.error("groupPath is empty for tool: " + toolWrapper.getShortName() + ", class: " + toolWrapper.getTool().getClass());
|
||||
return getRelativeRootNode(groupedBySeverity, errorLevel);
|
||||
}
|
||||
ConcurrentMap<String[], InspectionGroupNode> map = myGroups.get(errorLevel);
|
||||
if (map == null) {
|
||||
map = ConcurrencyUtil.cacheOrGet(myGroups, errorLevel, ConcurrentCollectionFactory.createMap(new TObjectHashingStrategy<String[]>() {
|
||||
@Override
|
||||
public int computeHashCode(String[] object) {
|
||||
return Arrays.hashCode(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(String[] o1, String[] o2) {
|
||||
return Arrays.equals(o1, o2);
|
||||
}
|
||||
}));
|
||||
}
|
||||
InspectionGroupNode group;
|
||||
if (groupedBySeverity) {
|
||||
group = map.get(groupPath);
|
||||
}
|
||||
else {
|
||||
group = null;
|
||||
for (Map<String[], InspectionGroupNode> groupMap : myGroups.values()) {
|
||||
if ((group = groupMap.get(groupPath)) != null) break;
|
||||
}
|
||||
}
|
||||
if (group == null) {
|
||||
if (isSingleInspectionRun) {
|
||||
return getRelativeRootNode(true, errorLevel);
|
||||
}
|
||||
group = map.computeIfAbsent(groupPath, p -> insertGroupNode(p, getRelativeRootNode(groupedBySeverity, errorLevel)));
|
||||
}
|
||||
return group;
|
||||
@Nullable
|
||||
@Override
|
||||
public TreePath[] getSelectionPaths() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
return super.getSelectionPaths();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private InspectionTreeNode getRelativeRootNode(boolean isGroupedBySeverity, HighlightDisplayLevel level) {
|
||||
if (isGroupedBySeverity) {
|
||||
InspectionSeverityGroupNode severityGroupNode = mySeverityGroupNodes.get(level);
|
||||
if (severityGroupNode == null) {
|
||||
InspectionSeverityGroupNode newNode = new InspectionSeverityGroupNode(myContext.getCurrentProfile().getProfileManager().getSeverityRegistrar(), level);
|
||||
severityGroupNode = ConcurrencyUtil.cacheOrGet(mySeverityGroupNodes, level, newNode);
|
||||
if (severityGroupNode == newNode) {
|
||||
InspectionTreeNode root = getRoot();
|
||||
root.insertByOrder(severityGroupNode, false);
|
||||
}
|
||||
}
|
||||
return severityGroupNode;
|
||||
InspectionTreeNode getToolProblemsRootNode(@NotNull InspectionToolWrapper toolWrapper,
|
||||
@NotNull HighlightDisplayLevel errorLevel,
|
||||
boolean groupedBySeverity,
|
||||
boolean isSingleInspectionRun) {
|
||||
InspectionTreeNode parent = getToolParentNode(toolWrapper, errorLevel, groupedBySeverity, isSingleInspectionRun);
|
||||
if (isSingleInspectionRun) {
|
||||
return parent;
|
||||
}
|
||||
return getRoot();
|
||||
return myModel.createInspectionNode(toolWrapper, myContext.getCurrentProfile(), parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private InspectionTreeNode getToolParentNode(@NotNull InspectionToolWrapper toolWrapper,
|
||||
@NotNull HighlightDisplayLevel errorLevel,
|
||||
boolean groupedBySeverity,
|
||||
boolean isSingleInspectionRun) {
|
||||
//synchronize
|
||||
if (!groupedBySeverity && isSingleInspectionRun) {
|
||||
return myModel.getRoot();
|
||||
}
|
||||
|
||||
InspectionTreeNode currentNode = groupedBySeverity
|
||||
? myModel.createSeverityGroupNode(myContext.getCurrentProfile().getProfileManager().getSeverityRegistrar(),
|
||||
errorLevel,
|
||||
myModel.getRoot())
|
||||
: myModel.getRoot();
|
||||
|
||||
if (isSingleInspectionRun) return currentNode;
|
||||
|
||||
String[] groupPath = toolWrapper.getGroupPath();
|
||||
if (groupPath.length == 0) {
|
||||
LOG.error("groupPath is empty for tool: " + toolWrapper.getShortName() + ", class: " + toolWrapper.getTool().getClass());
|
||||
}
|
||||
|
||||
for (String subGroup : groupPath) {
|
||||
currentNode = myModel.createGroupNode(subGroup, currentNode);
|
||||
}
|
||||
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
public boolean areDescriptorNodesSelected() {
|
||||
@@ -343,10 +389,13 @@ public class InspectionTree extends Tree {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getSelectedProblemCount(boolean allowSuppressed) {
|
||||
public int getSelectedProblemCount() {
|
||||
int count = 0;
|
||||
for (TreePath path : TreeUtil.selectMaximals(getSelectionPaths())) {
|
||||
count += ((InspectionTreeNode)path.getLastPathComponent()).getProblemCount(allowSuppressed);
|
||||
LevelAndCount[] levels = ((InspectionTreeNode)path.getLastPathComponent()).getProblemLevels();
|
||||
for (LevelAndCount level : levels) {
|
||||
count += level.getCount();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -358,58 +407,57 @@ public class InspectionTree extends Tree {
|
||||
!node.isQuickFixAppliedFromView()));
|
||||
}
|
||||
|
||||
private void nodeStructureChanged(InspectionTreeNode node) {
|
||||
((DefaultTreeModel)getModel()).nodeStructureChanged(node);
|
||||
}
|
||||
|
||||
public void queueUpdate() {
|
||||
((InspectionRootNode) getRoot()).getUpdater().update(true);
|
||||
}
|
||||
|
||||
public void restoreExpansionAndSelection(boolean treeNodesMightChange) {
|
||||
myState.restoreExpansionAndSelection(this, treeNodesMightChange);
|
||||
}
|
||||
|
||||
public void removeSelectedProblems() {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
TreePath[] selected = getSelectionPaths();
|
||||
if (selected == null) return;
|
||||
if (!getContext().getUIOptions().FILTER_RESOLVED_ITEMS) {
|
||||
for (TreePath path : selected) {
|
||||
InspectionTreeNode node = (InspectionTreeNode)path.getLastPathComponent();
|
||||
myModel.traverse(node, n -> {
|
||||
n.dropProblemCountCaches();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
synchronized (getContext().getView().getTreeStructureUpdateLock()) {
|
||||
TreePath[] selected = getSelectionPaths();
|
||||
if (selected == null) return;
|
||||
Set<InspectionTreeNode> processedNodes = new THashSet<>();
|
||||
List<InspectionTreeNode> toRemove = new ArrayList<>();
|
||||
List<TreePath> pathsToSelect = new ArrayList<>();
|
||||
for (TreePath path : selected) {
|
||||
Object[] nodePath = path.getPath();
|
||||
Set<InspectionTreeNode> processedNodes = new THashSet<>();
|
||||
List<InspectionTreeNode> toRemove = new ArrayList<>();
|
||||
List<TreePath> pathsToSelect = new ArrayList<>();
|
||||
for (TreePath path : selected) {
|
||||
Object[] nodePath = path.getPath();
|
||||
|
||||
// ignore root
|
||||
for (int i = 1; i < nodePath.length; i++) {
|
||||
InspectionTreeNode node = (InspectionTreeNode) nodePath[i];
|
||||
if (!processedNodes.add(node)) break;
|
||||
// ignore root
|
||||
for (int i = 1; i < nodePath.length; i++) {
|
||||
InspectionTreeNode node = (InspectionTreeNode) nodePath[i];
|
||||
if (!processedNodes.add(node)) continue;
|
||||
|
||||
if (shouldDelete(node)) {
|
||||
toRemove.add(node);
|
||||
TreePath toSelect = getParentPath(path, nodePath.length - i);
|
||||
if (toSelect != null) {
|
||||
pathsToSelect.add(toSelect);
|
||||
}
|
||||
break;
|
||||
if (shouldDelete(node)) {
|
||||
toRemove.add(node);
|
||||
TreePath toSelect = getParentPath(path, nodePath.length - i);
|
||||
if (toSelect != null) {
|
||||
pathsToSelect.add(toSelect);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove.isEmpty()) return;
|
||||
DefaultTreeModel model = (DefaultTreeModel)getModel();
|
||||
for (InspectionTreeNode node : toRemove) {
|
||||
TreeNode parent = node.getParent();
|
||||
if (parent != null) {
|
||||
model.removeNodeFromParent(node);
|
||||
}
|
||||
}
|
||||
|
||||
TreeUtil.selectPath(this, TreeUtil.findCommonPath(pathsToSelect.toArray(new TreePath[0])));
|
||||
}
|
||||
|
||||
if (toRemove.isEmpty()) return;
|
||||
Set<InspectionTreeNode> parents = new THashSet<>();
|
||||
for (InspectionTreeNode node : toRemove) {
|
||||
InspectionTreeNode parent = node.getParent();
|
||||
if (parent != null) {
|
||||
myModel.remove(node);
|
||||
parents.add(parent);
|
||||
}
|
||||
}
|
||||
|
||||
for (InspectionTreeNode parent : parents) {
|
||||
parent.dropProblemCountCaches();
|
||||
}
|
||||
TreeUtil.selectPath(this, TreeUtil.findCommonPath(pathsToSelect.toArray(new TreePath[0])));
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
@@ -425,10 +473,16 @@ public class InspectionTree extends Tree {
|
||||
private boolean shouldDelete(InspectionTreeNode node) {
|
||||
if (node instanceof RefElementNode) {
|
||||
RefElementNode refElementNode = (RefElementNode)node;
|
||||
RefEntity refEntity = refElementNode.getElement();
|
||||
if (refEntity == null || isEntityExcludedOrResolvedRecursively(refEntity, refElementNode.getPresentation())) {
|
||||
InspectionToolPresentation presentation = refElementNode.getPresentation();
|
||||
RefEntity element = refElementNode.getElement();
|
||||
if (element == null ||
|
||||
presentation.isProblemResolved(element) ||
|
||||
presentation.isExcluded(element) ||
|
||||
presentation.isSuppressed(element)) {
|
||||
return true;
|
||||
}
|
||||
List<? extends InspectionTreeNode> children = node.getChildren();
|
||||
return !children.isEmpty() && children.stream().allMatch(this::shouldDelete);
|
||||
}
|
||||
else if (node instanceof ProblemDescriptionNode) {
|
||||
ProblemDescriptionNode problemDescriptionNode = (ProblemDescriptionNode)node;
|
||||
@@ -439,7 +493,7 @@ public class InspectionTree extends Tree {
|
||||
}
|
||||
}
|
||||
else if (node instanceof InspectionGroupNode || node instanceof InspectionSeverityGroupNode || node instanceof InspectionModuleNode || node instanceof InspectionPackageNode) {
|
||||
return IntStream.range(0, node.getChildCount()).mapToObj(i -> (InspectionTreeNode)node.getChildAt(i)).allMatch(this::shouldDelete);
|
||||
return node.getChildren().stream().allMatch(this::shouldDelete);
|
||||
}
|
||||
else if (node instanceof InspectionNode) {
|
||||
InspectionToolPresentation presentation = myContext.getPresentation(((InspectionNode)node).getToolWrapper());
|
||||
@@ -452,80 +506,16 @@ public class InspectionTree extends Tree {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isEntityExcludedOrResolvedRecursively(RefEntity key, InspectionToolPresentation presentation) {
|
||||
if (presentation.isProblemResolved(key) ||
|
||||
presentation.isExcluded(key) ||
|
||||
presentation.isSuppressed(key)) {
|
||||
return true;
|
||||
}
|
||||
List<RefEntity> children = key.getChildren();
|
||||
return !children.isEmpty() && children.stream().allMatch(entity -> isEntityExcludedOrResolvedRecursively(entity, presentation));
|
||||
}
|
||||
|
||||
public InspectionTreeState getTreeState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
public void setTreeState(@NotNull InspectionTreeState treeState) {
|
||||
myState = treeState;
|
||||
}
|
||||
|
||||
private class ExpandListener implements TreeWillExpandListener {
|
||||
@Override
|
||||
public void treeWillExpand(TreeExpansionEvent event) {
|
||||
final InspectionTreeNode node = (InspectionTreeNode)event.getPath().getLastPathComponent();
|
||||
myState.getExpandedUserObjects().add(node.getUserObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void treeWillCollapse(TreeExpansionEvent event) {
|
||||
InspectionTreeNode node = (InspectionTreeNode)event.getPath().getLastPathComponent();
|
||||
myState.getExpandedUserObjects().remove(node.getUserObject());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GlobalInspectionContextImpl getContext() {
|
||||
return myContext;
|
||||
}
|
||||
|
||||
private InspectionGroupNode insertGroupNode(@NotNull String[] groupPath, InspectionTreeNode parent) {
|
||||
InspectionTreeNode currentNode = parent;
|
||||
|
||||
for (int groupIdx = 0; groupIdx < groupPath.length; groupIdx++) {
|
||||
String subGroup = groupPath[groupIdx];
|
||||
|
||||
InspectionTreeNode next = null;
|
||||
for (int i = 0; i < currentNode.getChildCount(); i++) {
|
||||
TreeNode child = currentNode.getChildAt(i);
|
||||
if (child instanceof InspectionGroupNode && ((InspectionGroupNode)child).getSubGroup().equals(subGroup)) {
|
||||
next = (InspectionTreeNode)child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next == null) {
|
||||
for (int i = groupIdx; i < groupPath.length; i++) {
|
||||
InspectionResultsView view = getContext().getView();
|
||||
if (view != null && !view.isDisposed()) {
|
||||
currentNode = currentNode.insertByOrder(new InspectionGroupNode(groupPath[i]), false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
currentNode = next;
|
||||
}
|
||||
}
|
||||
|
||||
return (InspectionGroupNode)currentNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String[] getGroupPath(@NotNull InspectionGroupNode node) {
|
||||
List<String> path = new ArrayList<>(2);
|
||||
while (true) {
|
||||
TreeNode parent = node.getParent();
|
||||
InspectionTreeNode parent = node.getParent();
|
||||
if (!(parent instanceof InspectionGroupNode)) break;
|
||||
node = (InspectionGroupNode)parent;
|
||||
path.add(node.getSubGroup());
|
||||
@@ -546,4 +536,138 @@ public class InspectionTree extends Tree {
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private class MyOccurrenceNavigator implements OccurenceNavigator {
|
||||
@Override
|
||||
public boolean hasNextOccurence() {
|
||||
return getNextNode(true) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPreviousOccurence() {
|
||||
return getNextNode(false) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OccurenceInfo goNextOccurence() {
|
||||
InspectionTreeNode node = getNextNode(true);
|
||||
if (node == null) return null;
|
||||
selectNode(node);
|
||||
return new OccurenceInfo(createDescriptorForNode(node), -1, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OccurenceInfo goPreviousOccurence() {
|
||||
InspectionTreeNode node = getNextNode(false);
|
||||
selectNode(node);
|
||||
return node == null ? null : new OccurenceInfo(createDescriptorForNode(node), -1, -1);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getNextOccurenceActionName() {
|
||||
return InspectionsBundle.message("inspection.action.go.next");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPreviousOccurenceActionName() {
|
||||
return InspectionsBundle.message("inspection.action.go.prev");
|
||||
}
|
||||
|
||||
private InspectionTreeNode getNextNode(boolean next) {
|
||||
InspectionTreeNode node = getSelectedNode();
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
return myModel.traverseFrom(node, next).filter(n -> n != node).filter(n -> isOccurrenceNode(n)).first();
|
||||
}
|
||||
|
||||
private InspectionTreeNode getSelectedNode() {
|
||||
TreePath path = getSelectionPath();
|
||||
if (path == null) return null;
|
||||
return (InspectionTreeNode)path.getLastPathComponent();
|
||||
}
|
||||
|
||||
private boolean isOccurrenceNode(@NotNull InspectionTreeNode node) {
|
||||
if (node.isExcluded()) {
|
||||
return false;
|
||||
}
|
||||
if (node instanceof RefElementNode) {
|
||||
final RefElementNode refNode = (RefElementNode)node;
|
||||
if (hasDescriptorUnder(refNode)) return false;
|
||||
final RefEntity element = refNode.getElement();
|
||||
return element != null && element.isValid();
|
||||
}
|
||||
return node instanceof ProblemDescriptionNode;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Navigatable createDescriptorForNode(@NotNull InspectionTreeNode node) {
|
||||
if (node.isExcluded()) {
|
||||
return null;
|
||||
}
|
||||
if (node instanceof RefElementNode) {
|
||||
final RefElementNode refNode = (RefElementNode)node;
|
||||
if (hasDescriptorUnder(refNode)) return null;
|
||||
final RefEntity element = refNode.getElement();
|
||||
if (element == null || !element.isValid()) return null;
|
||||
if (element instanceof RefElement) {
|
||||
return getOpenFileDescriptor((RefElement)element);
|
||||
}
|
||||
}
|
||||
else if (node instanceof ProblemDescriptionNode) {
|
||||
ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node;
|
||||
boolean isValid = problemNode.isValid() && (!problemNode.isQuickFixAppliedFromView() ||
|
||||
problemNode.calculateIsValid());
|
||||
return isValid
|
||||
? navigate(problemNode.getDescriptor())
|
||||
: InspectionResultsViewUtil.getNavigatableForInvalidNode(problemNode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private Navigatable navigate(final CommonProblemDescriptor descriptor) {
|
||||
return InspectionResultsView.getSelectedNavigatable(descriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Navigatable getOpenFileDescriptor(final RefElement refElement) {
|
||||
PsiElement psiElement = refElement.getPsiElement();
|
||||
if (psiElement == null) return null;
|
||||
final PsiFile containingFile = psiElement.getContainingFile();
|
||||
if (containingFile == null) return null;
|
||||
VirtualFile file = containingFile.getVirtualFile();
|
||||
if (file == null) return null;
|
||||
return PsiNavigationSupport.getInstance().createNavigatable(refElement.getRefManager().getProject(), file,
|
||||
psiElement.getTextOffset());
|
||||
}
|
||||
|
||||
private boolean hasDescriptorUnder(RefElementNode node) {
|
||||
InspectionTreeNode current = node;
|
||||
while (current != null && current.getChildCount() != 0) {
|
||||
current = current.getChildAt(0);
|
||||
if (current instanceof ProblemDescriptionNode) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private TreePath getPathFor(InspectionTreeNode node) {
|
||||
TreePath result = TreePathUtil.pathToTreeNode(node);
|
||||
|
||||
Stack<TreePath> s = new Stack<>();
|
||||
TreePath current = result;
|
||||
while (current != null) {
|
||||
s.add(current);
|
||||
current = current.getParentPath();
|
||||
}
|
||||
while (!s.isEmpty()) {
|
||||
TreePath p = s.pop();
|
||||
expandPath(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ class InspectionTreeCellRenderer extends ColoredTreeCellRenderer {
|
||||
boolean hasFocus) {
|
||||
InspectionTreeNode node = (InspectionTreeNode)value;
|
||||
|
||||
append(node.toString(),
|
||||
append(node.getPresentableText(),
|
||||
patchMainTextAttrs(node, node.appearsBold()
|
||||
? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES
|
||||
: getMainForegroundAttributes(node)));
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
|
||||
import com.intellij.codeInspection.offlineViewer.OfflineDescriptorResolveResult;
|
||||
import com.intellij.codeInspection.offlineViewer.OfflineProblemDescriptorNode;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.ui.tree.BaseTreeModel;
|
||||
import com.intellij.ui.tree.TreePathUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.BidirectionalMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
import com.intellij.util.containers.TreeTraversal;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class InspectionTreeModel extends BaseTreeModel<InspectionTreeNode> {
|
||||
private static final Logger LOG = Logger.getInstance(InspectionTreeModel.class);
|
||||
private final InspectionRootNode myRoot = new InspectionRootNode(this);
|
||||
private final Map<InspectionTreeNode, Children> myChildren = new ConcurrentHashMap<>();
|
||||
private final Map<InspectionTreeNode, InspectionTreeNode> myParents = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public int getIndexOfChild(Object object, Object child) {
|
||||
return Collections.binarySearch(getChildren(object), (InspectionTreeNode)child, InspectionResultsViewComparator.INSTANCE);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
treeNodesChanged(null, null, null);
|
||||
}
|
||||
|
||||
private static class Children {
|
||||
private static final InspectionTreeNode[] EMPTY_ARRAY = new InspectionTreeNode[0];
|
||||
|
||||
private volatile InspectionTreeNode[] myChildren = EMPTY_ARRAY;
|
||||
private final BidirectionalMap<Object, InspectionTreeNode> myUserObject2Node = new BidirectionalMap<>();
|
||||
}
|
||||
|
||||
public InspectionTreeModel() {}
|
||||
|
||||
@Override
|
||||
public List<? extends InspectionTreeNode> getChildren(Object parent) {
|
||||
Children nodes = myChildren.get(((InspectionTreeNode)parent));
|
||||
return nodes == null ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(nodes.myChildren));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionRootNode getRoot() {
|
||||
return myRoot;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InspectionTreeNode getParent(InspectionTreeNode node) {
|
||||
return myParents.get(node);
|
||||
}
|
||||
|
||||
public void traverse(InspectionTreeNode node, Processor<? super InspectionTreeNode> processor) {
|
||||
TreeTraversal.PRE_ORDER_DFS.traversal(node, n -> getChildren(n)).processEach(processor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JBIterable<InspectionTreeNode> traverseFrom(InspectionTreeNode node, boolean direction) {
|
||||
return JBIterable.generate(node, n -> getParent(n)).filter(n -> getParent(n) != null).flatMap(n1 -> {
|
||||
InspectionTreeNode p = getParent(n1);
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
List<? extends InspectionTreeNode> children = p.getChildren();
|
||||
int idx = getIndexOfChild(p, n1);
|
||||
InspectionTreeNode[] arr = children.toArray(InspectionTreeNode.EMPTY_ARRAY);
|
||||
List<? extends InspectionTreeNode> sublist = Arrays.asList(arr).subList(idx + ((n1 == node) ? 0 : 1), children.size());
|
||||
return TreeTraversal.PRE_ORDER_DFS.traversal(sublist, (InspectionTreeNode n) -> direction ? getChildren(n) : ContainerUtil.reverse(getChildren(n)));
|
||||
});
|
||||
}
|
||||
|
||||
public void removeChild(@NotNull InspectionTreeNode node, int childIndex) {
|
||||
InspectionTreeNode removed = myChildren.get(node).myChildren[childIndex];
|
||||
remove(removed);
|
||||
treeNodesChanged(null, null, null);
|
||||
treeStructureChanged(null, null, null);
|
||||
}
|
||||
|
||||
public void removeChildren(@NotNull InspectionTreeNode node) {
|
||||
doRemove(node, node);
|
||||
treeNodesChanged(null, null, null);
|
||||
treeStructureChanged(null, null, null);
|
||||
}
|
||||
|
||||
public void remove(@NotNull InspectionTreeNode node) {
|
||||
doRemove(node, null);
|
||||
treeNodesChanged(null, null, null);
|
||||
treeStructureChanged(null, null, null);
|
||||
}
|
||||
|
||||
private synchronized void doRemove(@NotNull InspectionTreeNode node, @Nullable InspectionTreeNode skip) {
|
||||
for (InspectionTreeNode child : getChildren(node)) {
|
||||
doRemove(child, skip);
|
||||
}
|
||||
if (node != skip) {
|
||||
InspectionTreeNode parent = myParents.remove(node);
|
||||
if (parent != null) {
|
||||
Children parentChildren = myChildren.get(parent);
|
||||
if (parentChildren != null) {
|
||||
parentChildren.myChildren = ArrayUtil.remove(parentChildren.myChildren, node);
|
||||
parentChildren.myUserObject2Node.removeValue(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearTree() {
|
||||
myChildren.clear();
|
||||
myParents.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionModuleNode createModuleNode(@NotNull Module module, @NotNull InspectionTreeNode parent) {
|
||||
return getOrAdd(module, () -> new InspectionModuleNode(module, this), parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionPackageNode createPackageNode(String packageName, @NotNull InspectionTreeNode parent) {
|
||||
return getOrAdd(packageName, () -> new InspectionPackageNode(packageName, this), parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionGroupNode createGroupNode(String group, @NotNull InspectionTreeNode parent) {
|
||||
return getOrAdd(group, () -> new InspectionGroupNode(group, this), parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionSeverityGroupNode createSeverityGroupNode(SeverityRegistrar severityRegistrar, HighlightDisplayLevel level, @NotNull InspectionTreeNode parent) {
|
||||
return getOrAdd(level, () -> new InspectionSeverityGroupNode(severityRegistrar, level, this), parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RefElementNode createRefElementNode(@Nullable RefEntity entity,
|
||||
@NotNull Supplier<? extends RefElementNode> supplier,
|
||||
@NotNull InspectionTreeNode parent) {
|
||||
return getOrAdd(entity, () -> ReadAction.compute(supplier::get), parent);
|
||||
}
|
||||
|
||||
public <T extends InspectionTreeNode> void createCustomNode(@NotNull Object userObject, @NotNull Supplier<T> supplier, @NotNull InspectionTreeNode parent) {
|
||||
getOrAdd(userObject, supplier, parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public InspectionNode createInspectionNode(@NotNull InspectionToolWrapper toolWrapper, InspectionProfileImpl profile, @NotNull InspectionTreeNode parent) {
|
||||
return getOrAdd(toolWrapper, () -> new InspectionNode(toolWrapper, profile, this), parent);
|
||||
}
|
||||
|
||||
public void createProblemDescriptorNode(RefEntity element,
|
||||
@NotNull CommonProblemDescriptor descriptor,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
@NotNull InspectionTreeNode parent) {
|
||||
getOrAdd(descriptor, () -> ReadAction.compute(() -> new ProblemDescriptionNode(element, descriptor, presentation, this)), parent);
|
||||
}
|
||||
|
||||
public void createOfflineProblemDescriptorNode(@NotNull OfflineProblemDescriptor offlineDescriptor,
|
||||
@NotNull OfflineDescriptorResolveResult resolveResult,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
@NotNull InspectionTreeNode parent) {
|
||||
getOrAdd(offlineDescriptor,
|
||||
() -> ReadAction.compute(() -> new OfflineProblemDescriptorNode(resolveResult, presentation, offlineDescriptor, this)),
|
||||
parent);
|
||||
}
|
||||
|
||||
private synchronized <T extends InspectionTreeNode> T getOrAdd(Object userObject, Supplier<T> supplier, InspectionTreeNode parent) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread());
|
||||
Children children = myChildren.computeIfAbsent(parent, __ -> new Children());
|
||||
if (userObject == null) {
|
||||
userObject = ObjectUtils.NULL;
|
||||
}
|
||||
InspectionTreeNode node = children.myUserObject2Node.get(userObject);
|
||||
if (node == null) {
|
||||
node = supplier.get();
|
||||
InspectionTreeNode finalNode = node;
|
||||
int idx = ReadAction.compute(() -> Arrays.binarySearch(children.myChildren, finalNode, InspectionResultsViewComparator.INSTANCE));
|
||||
if (idx >= 0) {
|
||||
InspectionTreeNode finalN = node;
|
||||
LOG.error(ReadAction.compute(() -> "idx = " + idx + " node = " + finalN + " parent = " + parent + " children " + Arrays.toString(children.myChildren)));
|
||||
}
|
||||
int insertionPoint = -idx - 1;
|
||||
children.myChildren = ArrayUtil.insert(children.myChildren, insertionPoint, node);
|
||||
myParents.put(node, parent);
|
||||
children.myUserObject2Node.put(userObject, node);
|
||||
|
||||
LOG.assertTrue(children.myChildren.length == children.myUserObject2Node.size());
|
||||
|
||||
if (node instanceof SuppressableInspectionTreeNode) {
|
||||
((SuppressableInspectionTreeNode)node).nodeAdded();
|
||||
}
|
||||
|
||||
TreePath path = TreePathUtil.pathToTreeNode(node);
|
||||
TreePath parentPath = path.getParentPath();
|
||||
treeNodesInserted(parentPath, null, null);
|
||||
while (parentPath != null) {
|
||||
treeStructureChanged(parentPath, null, null);
|
||||
parentPath = parentPath.getParentPath();
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (T)node;
|
||||
}
|
||||
}
|
||||
@@ -5,27 +5,23 @@ package com.intellij.codeInspection.ui;
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.util.AtomicClearableLazyValue;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.WeakInterner;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
public abstract class InspectionTreeNode implements TreeNode {
|
||||
static final InspectionTreeNode[] EMPTY_ARRAY = new InspectionTreeNode[0];
|
||||
private static final WeakInterner<LevelAndCount[]> LEVEL_AND_COUNT_INTERNER = new WeakInterner<>(new TObjectHashingStrategy<LevelAndCount[]>() {
|
||||
@Override
|
||||
public int computeHashCode(LevelAndCount[] object) {
|
||||
@@ -55,10 +51,11 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
return doesNeedInternProblemLevels() ? LEVEL_AND_COUNT_INTERNER.intern(arr) : arr;
|
||||
}
|
||||
};
|
||||
protected volatile InspectionTreeUpdater myUpdater;
|
||||
@NotNull
|
||||
private final InspectionTreeModel myModel;
|
||||
|
||||
protected InspectionTreeNode(Object userObject) {
|
||||
super(userObject);
|
||||
protected InspectionTreeNode(@NotNull InspectionTreeModel model) {
|
||||
myModel = model;
|
||||
}
|
||||
|
||||
protected boolean doesNeedInternProblemLevels() {
|
||||
@@ -82,7 +79,7 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
InspectionTreeNode current = this;
|
||||
while (current != null) {
|
||||
current.myProblemLevels.drop();
|
||||
current = (InspectionTreeNode)current.getParent();
|
||||
current = current.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +88,7 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
}
|
||||
|
||||
protected void visitProblemSeverities(@NotNull TObjectIntHashMap<HighlightDisplayLevel> counter) {
|
||||
Enumeration enumeration = children();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement();
|
||||
for (InspectionTreeNode child : getChildren()) {
|
||||
for (LevelAndCount levelAndCount : child.getProblemLevels()) {
|
||||
if (!counter.adjustValue(levelAndCount.getLevel(), levelAndCount.getCount())) {
|
||||
counter.put(levelAndCount.getLevel(), levelAndCount.getCount());
|
||||
@@ -102,29 +97,19 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
public int getProblemCount(boolean allowSuppressed) {
|
||||
int sum = 0;
|
||||
Enumeration enumeration = children();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement();
|
||||
sum += child.getProblemCount(allowSuppressed);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isExcluded() {
|
||||
Enumeration enumeration = children();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement();
|
||||
List<? extends InspectionTreeNode> children = getChildren();
|
||||
for (InspectionTreeNode child : children) {
|
||||
if (!child.isExcluded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return getChildCount() != 0;
|
||||
|
||||
return !children.isEmpty() ;
|
||||
}
|
||||
|
||||
public boolean appearsBold() {
|
||||
@@ -137,85 +122,27 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
}
|
||||
|
||||
public void excludeElement() {
|
||||
Enumeration enumeration = children();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement();
|
||||
for (InspectionTreeNode child : getChildren()) {
|
||||
child.excludeElement();
|
||||
}
|
||||
dropProblemCountCaches();
|
||||
}
|
||||
|
||||
public void amnestyElement() {
|
||||
Enumeration enumeration = children();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement();
|
||||
for (InspectionTreeNode child : getChildren()) {
|
||||
child.amnestyElement();
|
||||
}
|
||||
dropProblemCountCaches();
|
||||
}
|
||||
|
||||
public InspectionTreeNode insertByOrder(InspectionTreeNode child, boolean allowDuplication) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (!allowDuplication) {
|
||||
int index = getIndex(child);
|
||||
if (index != -1) {
|
||||
return (InspectionTreeNode)getChildAt(index);
|
||||
}
|
||||
}
|
||||
int index = TreeUtil.indexedBinarySearch(this, child, InspectionResultsViewComparator.getInstance());
|
||||
if (!allowDuplication && index >= 0) {
|
||||
return (InspectionTreeNode)getChildAt(index);
|
||||
}
|
||||
insert(child, Math.abs(index + 1));
|
||||
return child;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(MutableTreeNode newChild) {
|
||||
super.add(newChild);
|
||||
if (myUpdater != null) {
|
||||
((InspectionTreeNode)newChild).propagateUpdater(myUpdater);
|
||||
dropProblemCountCaches();
|
||||
myUpdater.updateWithPreviewPanel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(MutableTreeNode newChild, int childIndex) {
|
||||
super.insert(newChild, childIndex);
|
||||
if (myUpdater != null) {
|
||||
((InspectionTreeNode)newChild).propagateUpdater(myUpdater);
|
||||
dropProblemCountCaches();
|
||||
myUpdater.updateWithPreviewPanel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int childIndex) {
|
||||
super.remove(childIndex);
|
||||
myModel.removeChild(this, childIndex);
|
||||
dropProblemCountCaches();
|
||||
}
|
||||
|
||||
protected void nodeAddedToTree() {
|
||||
}
|
||||
|
||||
private void propagateUpdater(InspectionTreeUpdater updater) {
|
||||
if (myUpdater != null) return;
|
||||
myUpdater = updater;
|
||||
Enumeration enumeration = children();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)enumeration.nextElement();
|
||||
child.propagateUpdater(updater);
|
||||
child.nodeAddedToTree();
|
||||
}
|
||||
}
|
||||
|
||||
public RefEntity getContainingFileLocalEntity() {
|
||||
final Enumeration children = children();
|
||||
RefEntity current = null;
|
||||
while (children.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)children.nextElement();
|
||||
for (InspectionTreeNode child : getChildren()) {
|
||||
final RefEntity entity = child.getContainingFileLocalEntity();
|
||||
if (entity == null || current != null) {
|
||||
return null;
|
||||
@@ -226,12 +153,53 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized TreeNode getParent() {
|
||||
return super.getParent();
|
||||
public boolean isLeaf() {
|
||||
return getChildren().isEmpty();
|
||||
}
|
||||
|
||||
public abstract String getPresentableText();
|
||||
|
||||
@NotNull
|
||||
public List<? extends InspectionTreeNode> getChildren() {
|
||||
return ObjectUtils.notNull(myModel.getChildren(this), Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setParent(MutableTreeNode newParent) {
|
||||
super.setParent(newParent);
|
||||
public InspectionTreeNode getParent() {
|
||||
return myModel.getParent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return getChildren().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionTreeNode getChildAt(int idx) {
|
||||
return getChildren().get(idx);
|
||||
}
|
||||
|
||||
public void removeAllChildren() {
|
||||
myModel.removeChildren(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode node) {
|
||||
return myModel.getIndexOfChild(this, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration children() {
|
||||
return Collections.enumeration(getChildren());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getPresentableText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.codeInspection.ui;
|
||||
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class InspectionTreeState {
|
||||
private final Set<Object> myExpandedUserObjects = new HashSet<>();
|
||||
private InspectionTreeSelectionPath mySelectionPath;
|
||||
|
||||
public Set<Object> getExpandedUserObjects() {
|
||||
return myExpandedUserObjects;
|
||||
}
|
||||
|
||||
public void setSelectionPath(TreePath selectionPath) {
|
||||
mySelectionPath = new InspectionTreeSelectionPath(selectionPath);
|
||||
}
|
||||
|
||||
public void restoreExpansionAndSelection(InspectionTree tree, boolean treeNodeMightChange) {
|
||||
restoreExpansionStatus((InspectionTreeNode)tree.getModel().getRoot(), tree);
|
||||
if (mySelectionPath != null) {
|
||||
mySelectionPath.restore(tree, treeNodeMightChange);
|
||||
} else {
|
||||
TreeUtil.selectFirstNode(tree);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreExpansionStatus(InspectionTreeNode node, InspectionTree tree) {
|
||||
if (getExpandedUserObjects().contains(node.getUserObject())) {
|
||||
//sortChildren(node);
|
||||
TreeNode[] pathToNode = node.getPath();
|
||||
tree.expandPath(new TreePath(pathToNode));
|
||||
Enumeration children = node.children();
|
||||
while (children.hasMoreElements()) {
|
||||
InspectionTreeNode childNode = (InspectionTreeNode)children.nextElement();
|
||||
restoreExpansionStatus(childNode, tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class InspectionTreeSelectionPath {
|
||||
private final Object[] myPath;
|
||||
private final int[] myIndices;
|
||||
|
||||
InspectionTreeSelectionPath(TreePath path) {
|
||||
myPath = path.getPath();
|
||||
myIndices = new int[myPath.length];
|
||||
for (int i = 0; i < myPath.length - 1; i++) {
|
||||
InspectionTreeNode node = (InspectionTreeNode)myPath[i];
|
||||
myIndices[i + 1] = getChildIndex(node, (InspectionTreeNode)myPath[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getChildIndex(InspectionTreeNode node, InspectionTreeNode child) {
|
||||
int idx = 0;
|
||||
Enumeration children = node.children();
|
||||
while (children.hasMoreElements()) {
|
||||
InspectionTreeNode ch = (InspectionTreeNode)children.nextElement();
|
||||
if (ch == child) break;
|
||||
idx++;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
public void restore(InspectionTree tree, boolean treeNodeMightChange) {
|
||||
tree.getSelectionModel().removeSelectionPaths(tree.getSelectionModel().getSelectionPaths());
|
||||
TreeUtil.selectPath(tree, restorePath(tree, treeNodeMightChange));
|
||||
}
|
||||
|
||||
private TreePath restorePath(InspectionTree tree, boolean treeNodeMightChange) {
|
||||
ArrayList<Object> newPath = new ArrayList<>();
|
||||
|
||||
newPath.add(tree.getModel().getRoot());
|
||||
restorePath(newPath, 1, treeNodeMightChange);
|
||||
return new TreePath(newPath.toArray());
|
||||
}
|
||||
|
||||
private void restorePath(ArrayList<Object> newPath, int idx, boolean treeNodeMightChange) {
|
||||
if (idx >= myPath.length) return;
|
||||
InspectionTreeNode oldNode = (InspectionTreeNode)myPath[idx];
|
||||
InspectionTreeNode newRoot = (InspectionTreeNode)newPath.get(idx - 1);
|
||||
|
||||
Enumeration children = newRoot.children();
|
||||
while (children.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)children.nextElement();
|
||||
if (treeNodeMightChange ? InspectionResultsViewComparator.getInstance().areEqual(child, oldNode) : child == oldNode) {
|
||||
newPath.add(child);
|
||||
restorePath(newPath, idx + 1, treeNodeMightChange);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Exactly same element not found. Trying to select somewhat near.
|
||||
int count = newRoot.getChildCount();
|
||||
if (count > 0) {
|
||||
if (myIndices[idx] < count) {
|
||||
newPath.add(newRoot.getChildAt(myIndices[idx]));
|
||||
}
|
||||
else {
|
||||
newPath.add(newRoot.getChildAt(count - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class InspectionTreeUpdater {
|
||||
private final MergingUpdateQueue myUpdateQueue;
|
||||
private final InspectionResultsView myView;
|
||||
private final AtomicBoolean myDoUpdatePreviewPanel = new AtomicBoolean(false);
|
||||
|
||||
public InspectionTreeUpdater(InspectionResultsView view) {
|
||||
myView = view;
|
||||
myUpdateQueue = new MergingUpdateQueue("InspectionView", 100, true, view, view);
|
||||
myUpdateQueue.setPassThrough(false);
|
||||
}
|
||||
|
||||
public void updateWithPreviewPanel() {
|
||||
myDoUpdatePreviewPanel.set(true);
|
||||
update(false);
|
||||
}
|
||||
|
||||
public void update(boolean force) {
|
||||
if (ApplicationManager.getApplication().isDispatchThread() && !force) {
|
||||
return;
|
||||
}
|
||||
myUpdateQueue.queue(new MyTreeUpdate());
|
||||
}
|
||||
|
||||
private class MyTreeUpdate extends Update {
|
||||
MyTreeUpdate() {
|
||||
super("inspection.view.update");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (myView.isDisposed()) return;
|
||||
final InspectionTree tree = myView.getTree();
|
||||
try {
|
||||
tree.setQueueUpdate(true);
|
||||
((DefaultTreeModel)tree.getModel()).reload();
|
||||
tree.restoreExpansionAndSelection(true);
|
||||
myView.openRightPanelIfNeed();
|
||||
if (myDoUpdatePreviewPanel.compareAndSet(true, false)) {
|
||||
myView.updateRightPanelLoading();
|
||||
}
|
||||
} finally {
|
||||
tree.setQueueUpdate(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(Update update) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-22
@@ -5,7 +5,6 @@ package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.Alarm;
|
||||
@@ -17,7 +16,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -121,7 +119,7 @@ class InspectionViewChangeAdapter extends PsiTreeChangeAdapter {
|
||||
if (pointer != null) {
|
||||
VirtualFile vFile = pointer.getVirtualFile();
|
||||
if (vFile == null || !vFile.isValid()) {
|
||||
dropNodeCache((SuppressableInspectionTreeNode)node);
|
||||
((SuppressableInspectionTreeNode)node).dropCache();
|
||||
if (!needUpdateUI[0]) {
|
||||
needUpdateUI[0] = true;
|
||||
}
|
||||
@@ -154,7 +152,7 @@ class InspectionViewChangeAdapter extends PsiTreeChangeAdapter {
|
||||
VirtualFile vFile = pointer.getVirtualFile();
|
||||
if (filesToCheck.contains(vFile)) {
|
||||
unPresentFiles.remove(vFile);
|
||||
dropNodeCache((SuppressableInspectionTreeNode)node);
|
||||
((SuppressableInspectionTreeNode)node).dropCache();
|
||||
if (!needUpdateUI[0]) {
|
||||
needUpdateUI[0] = true;
|
||||
}
|
||||
@@ -168,9 +166,7 @@ class InspectionViewChangeAdapter extends PsiTreeChangeAdapter {
|
||||
nodeProcessor = CompositeProcessor.combine(fileCheckProcessor, nodeProcessor);
|
||||
}
|
||||
|
||||
synchronized (myView.getTreeStructureUpdateLock()) {
|
||||
processNodesIfNeed(myView.getTree().getRoot(), Objects.requireNonNull(nodeProcessor));
|
||||
}
|
||||
myView.getTree().getInspectionTreeModel().traverse(myView.getTree().getInspectionTreeModel().getRoot(), nodeProcessor);
|
||||
|
||||
if (!unPresentFiles.isEmpty()) {
|
||||
myUnPresentEditedFiles.addAll(unPresentFiles);
|
||||
@@ -178,24 +174,12 @@ class InspectionViewChangeAdapter extends PsiTreeChangeAdapter {
|
||||
|
||||
if (needUpdateUI[0] && !myAlarm.isDisposed()) {
|
||||
myAlarm.cancelAllRequests();
|
||||
myAlarm.addRequest(() -> myView.resetTree(), 100, ModalityState.NON_MODAL);
|
||||
//TODO replace with more accurate
|
||||
myAlarm.addRequest(() -> myView.getTree().getInspectionTreeModel().reload(), 100, ModalityState.NON_MODAL);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
private static void dropNodeCache(SuppressableInspectionTreeNode node) {
|
||||
ReadAction.run(() -> node.dropCache());
|
||||
}
|
||||
|
||||
private static void processNodesIfNeed(InspectionTreeNode node, Processor<? super InspectionTreeNode> processor) {
|
||||
if (processor.process(node)) {
|
||||
final int count = node.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
processNodesIfNeed((InspectionTreeNode)node.getChildAt(i), processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompositeProcessor<X> implements Processor<X> {
|
||||
private final Processor<? super X> myFirstProcessor;
|
||||
private boolean myFirstFinished;
|
||||
@@ -207,7 +191,6 @@ class InspectionViewChangeAdapter extends PsiTreeChangeAdapter {
|
||||
mySecondProcessor = secondProcessor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean process(X x) {
|
||||
if (!myFirstFinished && !myFirstProcessor.process(x)) {
|
||||
|
||||
+3
-6
@@ -18,12 +18,9 @@ package com.intellij.codeInspection.ui;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.labels.LinkLabel;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
@@ -70,11 +67,11 @@ public class InspectionViewNavigationPanel extends JPanel implements InspectionT
|
||||
myLinks.removeAll();
|
||||
myLinks.add(Box.createVerticalStrut(JBUI.scale(10)));
|
||||
for (int i = 0; i < currentChildrenCount; i++) {
|
||||
final TreeNode child = myNode.getChildAt(i);
|
||||
final LinkLabel link = new LinkLabel(child.toString(), null) {
|
||||
final InspectionTreeNode child = myNode.getChildAt(i);
|
||||
final LinkLabel link = new LinkLabel(child.getPresentableText(), null) {
|
||||
@Override
|
||||
public void doClick() {
|
||||
TreeUtil.selectInTree((DefaultMutableTreeNode)child, true, myTree);
|
||||
myTree.selectNode(child);
|
||||
}
|
||||
};
|
||||
link.setBorder(JBUI.Borders.empty(1, 17, 3, 1));
|
||||
|
||||
+2
-1
@@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -115,7 +116,7 @@ public class InspectionViewSuppressActionHolder {
|
||||
if (!myElementLanguage.equals(that.myElementLanguage)) return false;
|
||||
if (!myFileBaseLanguage.equals(that.myFileBaseLanguage)) return false;
|
||||
if (!myFileLanguages.equals(that.myFileLanguages)) return false;
|
||||
if (myInjectionDescriptor != null ? !myInjectionDescriptor.equals(that.myInjectionDescriptor) : that.myInjectionDescriptor != null) {
|
||||
if (!Objects.equals(myInjectionDescriptor, that.myInjectionDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.profile.codeInspection.InspectionProfileManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -35,15 +36,17 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
|
||||
public ProblemDescriptionNode(RefEntity element,
|
||||
@NotNull CommonProblemDescriptor descriptor,
|
||||
@NotNull InspectionToolPresentation presentation) {
|
||||
this(element, descriptor, presentation, null);
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
@NotNull InspectionTreeModel model) {
|
||||
this(element, descriptor, presentation, null, model);
|
||||
}
|
||||
|
||||
protected ProblemDescriptionNode(@Nullable RefEntity element,
|
||||
CommonProblemDescriptor descriptor,
|
||||
@NotNull InspectionToolPresentation presentation,
|
||||
@Nullable IntSupplier lineNumberCounter) {
|
||||
super(descriptor, presentation);
|
||||
@Nullable IntSupplier lineNumberCounter,
|
||||
@NotNull InspectionTreeModel model) {
|
||||
super(presentation, model);
|
||||
myElement = element;
|
||||
myDescriptor = descriptor;
|
||||
myLevel = ObjectUtils.notNull(calculatePreciseLevel(element, descriptor, presentation), () -> {
|
||||
@@ -111,7 +114,6 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
return myElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CommonProblemDescriptor getDescriptor() {
|
||||
return myDescriptor;
|
||||
@@ -180,4 +182,17 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
final String text = super.getTailText();
|
||||
return text == null ? "" : text;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<PsiElement, CommonProblemDescriptor> getSuppressContent() {
|
||||
RefEntity refElement = getElement();
|
||||
CommonProblemDescriptor descriptor = getDescriptor();
|
||||
PsiElement element = descriptor instanceof ProblemDescriptor
|
||||
? ((ProblemDescriptor)descriptor).getPsiElement()
|
||||
: refElement instanceof RefElement
|
||||
? ((RefElement)refElement).getPsiElement()
|
||||
: null;
|
||||
return Pair.create(element, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-7
@@ -70,10 +70,16 @@ public class QuickFixPreviewPanelFactory {
|
||||
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
|
||||
boolean hasComponents = false;
|
||||
|
||||
final int actualProblemCount = myView.getTree().getContext().getPresentation(myWrapper).getProblemsCount(myView.getTree());
|
||||
if (actualProblemCount > 1 || (actualProblemCount == 1 && multipleDescriptors)) {
|
||||
add(getLabel(actualProblemCount));
|
||||
hasComponents = true;
|
||||
InspectionTree tree = myView.getTree();
|
||||
InspectionToolPresentation presentation = tree.getContext().getPresentation(myWrapper);
|
||||
final boolean showProblemCount = presentation.showProblemCount();
|
||||
|
||||
if (showProblemCount) {
|
||||
final int actualProblemCount = tree.getSelectedProblemCount();
|
||||
if (actualProblemCount > 1 || (actualProblemCount == 1 && multipleDescriptors)) {
|
||||
add(getLabel(actualProblemCount));
|
||||
hasComponents = true;
|
||||
}
|
||||
}
|
||||
|
||||
final DefaultActionGroup actions = new DefaultActionGroup();
|
||||
@@ -197,7 +203,7 @@ public class QuickFixPreviewPanelFactory {
|
||||
setBorder(JBUI.Borders.empty(16, 9, 13, 0));
|
||||
AsyncProcessIcon waitingIcon = new AsyncProcessIcon("Inspection preview panel updating...");
|
||||
Disposer.register(this, waitingIcon);
|
||||
myWaitingLabel = getLabel(myView.getTree().getSelectedProblemCount(false));
|
||||
myWaitingLabel = getLabel(myView.getTree() .getSelectedProblemCount());
|
||||
add(myWaitingLabel);
|
||||
add(waitingIcon);
|
||||
}
|
||||
@@ -207,7 +213,7 @@ public class QuickFixPreviewPanelFactory {
|
||||
if (myWaitingLabel != null) {
|
||||
myWaitingLabel.clear();
|
||||
final InspectionTree tree = myView.getTree();
|
||||
appendTextToLabel(myWaitingLabel, tree.getSelectedProblemCount(false));
|
||||
appendTextToLabel(myWaitingLabel, tree.getSelectedProblemCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +231,7 @@ public class QuickFixPreviewPanelFactory {
|
||||
private static SimpleColoredComponent getLabel(int problemsCount) {
|
||||
SimpleColoredComponent label = new SimpleColoredComponent();
|
||||
appendTextToLabel(label, problemsCount);
|
||||
label.setBorder(JBUI.Borders.empty(0, 0, 0, 2));
|
||||
label.setBorder(JBUI.Borders.emptyRight(2));
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,24 +9,24 @@ import com.intellij.codeInspection.reference.RefDirectory;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
private volatile boolean myHasDescriptorsUnder;
|
||||
private volatile CommonProblemDescriptor mySingleDescriptor;
|
||||
private final Icon myIcon;
|
||||
public RefElementNode(@Nullable RefEntity userObject, @NotNull InspectionToolPresentation presentation) {
|
||||
super(userObject, presentation);
|
||||
final RefEntity refEntity = getElement();
|
||||
@Nullable private final RefEntity myRefEntity;
|
||||
|
||||
public RefElementNode(@Nullable RefEntity refEntity, @NotNull InspectionToolPresentation presentation, InspectionTreeModel model) {
|
||||
super(presentation, model);
|
||||
myRefEntity = refEntity;
|
||||
myIcon = refEntity == null ? null : refEntity.getIcon(false);
|
||||
}
|
||||
|
||||
@@ -35,14 +35,10 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
return getElement() != null && getPresentation().isSuppressed(getElement());
|
||||
}
|
||||
|
||||
boolean hasDescriptorsUnder() {
|
||||
return myHasDescriptorsUnder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RefEntity getElement() {
|
||||
return (RefEntity)getUserObject();
|
||||
return myRefEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,28 +91,6 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
super.amnestyElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(MutableTreeNode newChild) {
|
||||
checkHasDescriptorUnder(newChild);
|
||||
super.add(newChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionTreeNode insertByOrder(InspectionTreeNode child, boolean allowDuplication) {
|
||||
checkHasDescriptorUnder(child);
|
||||
return super.insertByOrder(child, allowDuplication);
|
||||
}
|
||||
|
||||
public void setProblem(CommonProblemDescriptor descriptor) {
|
||||
mySingleDescriptor = descriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CommonProblemDescriptor getDescriptor() {
|
||||
return mySingleDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefEntity getContainingFileLocalEntity() {
|
||||
final RefEntity element = getElement();
|
||||
@@ -156,16 +130,11 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
return isLeaf() ? "" : null;
|
||||
}
|
||||
|
||||
private void checkHasDescriptorUnder(MutableTreeNode newChild) {
|
||||
if (myHasDescriptorsUnder) return;
|
||||
if (newChild instanceof ProblemDescriptionNode ||
|
||||
newChild instanceof RefElementNode && ((RefElementNode)newChild).hasDescriptorsUnder()) {
|
||||
myHasDescriptorsUnder = true;
|
||||
TreeNode parent = getParent();
|
||||
while (parent instanceof RefElementNode) {
|
||||
((RefElementNode)parent).myHasDescriptorsUnder = true;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
@NotNull
|
||||
@Override
|
||||
public Pair<PsiElement, CommonProblemDescriptor> getSuppressContent() {
|
||||
RefEntity refElement = getElement();
|
||||
PsiElement element = refElement instanceof RefElement ? ((RefElement)refElement).getPsiElement() : null;
|
||||
return Pair.create(element, null);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-35
@@ -4,11 +4,10 @@
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.SuppressIntentionAction;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.concurrency.ConcurrentCollectionFactory;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -17,7 +16,6 @@ import com.intellij.util.containers.Interner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
@@ -31,11 +29,20 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
private volatile Boolean myValid;
|
||||
private volatile NodeState myPreviousState;
|
||||
|
||||
SuppressableInspectionTreeNode(Object userObject, @NotNull InspectionToolPresentation presentation) {
|
||||
super(userObject);
|
||||
SuppressableInspectionTreeNode(@NotNull InspectionToolPresentation presentation, @NotNull InspectionTreeModel model) {
|
||||
super(model);
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
void nodeAdded() {
|
||||
dropProblemCountCaches();
|
||||
ReadAction.run(() -> {
|
||||
myPresentableName = calculatePresentableName();
|
||||
myValid = calculateIsValid();
|
||||
myAvailableSuppressActions = calculateAvailableSuppressActions();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doesNeedInternProblemLevels() {
|
||||
return true;
|
||||
@@ -47,7 +54,7 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
}
|
||||
|
||||
public boolean canSuppress() {
|
||||
return isLeaf();
|
||||
return getChildren().isEmpty();
|
||||
}
|
||||
|
||||
public abstract boolean isAlreadySuppressedFromView();
|
||||
@@ -64,11 +71,6 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemCount(boolean allowSuppressed) {
|
||||
return !isExcluded() && isValid() && !isQuickFixAppliedFromView() && (allowSuppressed || !isAlreadySuppressedFromView()) ? 1 : 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized Set<SuppressIntentionAction> getAvailableSuppressActions() {
|
||||
Set<SuppressIntentionAction> actions = myAvailableSuppressActions;
|
||||
@@ -86,9 +88,6 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
@Nullable
|
||||
public abstract RefEntity getElement();
|
||||
|
||||
@Nullable
|
||||
public abstract CommonProblemDescriptor getDescriptor();
|
||||
|
||||
@Override
|
||||
public final synchronized boolean isValid() {
|
||||
Boolean valid = myValid;
|
||||
@@ -100,7 +99,7 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized String toString() {
|
||||
public final synchronized String getPresentableText() {
|
||||
String name = myPresentableName;
|
||||
if (name == null) {
|
||||
name = calculatePresentableName();
|
||||
@@ -121,13 +120,6 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
return !isValid() ? "No longer valid" : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nodeAddedToTree() {
|
||||
myPresentableName = calculatePresentableName();
|
||||
myValid = calculateIsValid();
|
||||
myAvailableSuppressActions = calculateAvailableSuppressActions();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<SuppressIntentionAction> calculateAvailableSuppressActions() {
|
||||
return getElement() == null
|
||||
@@ -136,16 +128,7 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final Pair<PsiElement, CommonProblemDescriptor> getSuppressContent() {
|
||||
RefEntity refElement = getElement();
|
||||
CommonProblemDescriptor descriptor = getDescriptor();
|
||||
PsiElement element = descriptor instanceof ProblemDescriptor
|
||||
? ((ProblemDescriptor)descriptor).getPsiElement()
|
||||
: refElement instanceof RefElement
|
||||
? ((RefElement)refElement).getPsiElement()
|
||||
: null;
|
||||
return Pair.create(element, descriptor);
|
||||
}
|
||||
public abstract Pair<PsiElement, CommonProblemDescriptor> getSuppressContent();
|
||||
|
||||
@NotNull
|
||||
private Set<SuppressIntentionAction> calculateAvailableSuppressActions(@NotNull Project project) {
|
||||
@@ -168,14 +151,19 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
protected abstract boolean calculateIsValid();
|
||||
|
||||
protected void dropCache() {
|
||||
ReadAction.run(() -> doDropCache());
|
||||
}
|
||||
|
||||
private void doDropCache() {
|
||||
myProblemLevels.drop();
|
||||
if (isQuickFixAppliedFromView() || isAlreadySuppressedFromView()) return;
|
||||
// calculate all data on background thread
|
||||
myValid = calculateIsValid();
|
||||
myPresentableName = calculatePresentableName();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
TreeNode child = getChildAt(i);
|
||||
|
||||
for (InspectionTreeNode child : getChildren()) {
|
||||
if (child instanceof SuppressableInspectionTreeNode) {
|
||||
((SuppressableInspectionTreeNode)child).dropCache();
|
||||
((SuppressableInspectionTreeNode)child).doDropCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.output.Format;
|
||||
@@ -120,7 +119,7 @@ public class ExportHTMLAction extends AnAction implements DumbAware {
|
||||
if (!outputDir.exists() && !outputDir.mkdirs()) {
|
||||
throw new IOException("Cannot create \'" + outputDir + "\'");
|
||||
}
|
||||
final InspectionTreeNode root = myView.getTree().getRoot();
|
||||
final InspectionTreeModel model = myView.getTree().getInspectionTreeModel();
|
||||
final Exception[] ex = new Exception[1];
|
||||
|
||||
final Set<String> visitedTools = new THashSet<>();
|
||||
@@ -128,7 +127,7 @@ public class ExportHTMLAction extends AnAction implements DumbAware {
|
||||
Format format = JDOMUtil.createFormat("\n");
|
||||
XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
|
||||
|
||||
TreeUtil.treeNodeTraverser(root).traverse().processEach(node -> {
|
||||
model.traverse(model.getRoot(), node -> {
|
||||
if (node instanceof InspectionNode) {
|
||||
InspectionNode toolNode = (InspectionNode)node;
|
||||
if (toolNode.isExcluded()) return true;
|
||||
|
||||
+1
-1
@@ -66,6 +66,6 @@ public class InvokeQuickFixAction extends AnAction {
|
||||
}
|
||||
|
||||
static boolean cantApplyFixes(InspectionResultsView view) {
|
||||
return view.isUpdating() && !view.getTree().areDescriptorNodesSelected();
|
||||
return !view.getTree().areDescriptorNodesSelected();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,21 +18,16 @@ package com.intellij.ide.actions.exclusion;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public interface ExclusionHandler<T extends MutableTreeNode> {
|
||||
public interface ExclusionHandler<Node> {
|
||||
DataKey<ExclusionHandler> EXCLUSION_HANDLER = DataKey.create("tree.exclusion.handler");
|
||||
|
||||
boolean isNodeExclusionAvailable(@NotNull T node);
|
||||
boolean isNodeExclusionAvailable(@NotNull Node node);
|
||||
|
||||
boolean isNodeExcluded(@NotNull T node);
|
||||
boolean isNodeExcluded(@NotNull Node node);
|
||||
|
||||
void excludeNode(@NotNull T node);
|
||||
void excludeNode(@NotNull Node node);
|
||||
|
||||
void includeNode(@NotNull T node);
|
||||
void includeNode(@NotNull Node node);
|
||||
|
||||
boolean isActionEnabled(boolean isExcludeAction);
|
||||
|
||||
|
||||
+4
-7
@@ -24,14 +24,11 @@ import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich.
|
||||
*/
|
||||
abstract class TreeNodeExclusionAction<T extends MutableTreeNode> extends AnAction {
|
||||
abstract class TreeNodeExclusionAction<T extends TreeNode> extends AnAction {
|
||||
private final static Logger LOG = Logger.getInstance(TreeNodeExclusionAction.class);
|
||||
|
||||
private final boolean myIsExclude;
|
||||
@@ -65,7 +62,7 @@ abstract class TreeNodeExclusionAction<T extends MutableTreeNode> extends AnActi
|
||||
final T node = (T)path.getLastPathComponent();
|
||||
TreeUtil.traverse(node, n -> {
|
||||
if (!exclusionProcessor.isNodeExclusionAvailable((T)n)) return true;
|
||||
final Boolean isNodeExcluded = exclusionProcessor.isNodeExcluded((T)n);
|
||||
boolean isNodeExcluded = exclusionProcessor.isNodeExcluded((T)n);
|
||||
if (myIsExclude != isNodeExcluded) {
|
||||
isEnabled[0] = true;
|
||||
return false;
|
||||
@@ -95,7 +92,7 @@ abstract class TreeNodeExclusionAction<T extends MutableTreeNode> extends AnActi
|
||||
final T node = (T)path.getLastPathComponent();
|
||||
TreeUtil.traverse(node, n -> {
|
||||
if (!exclusionProcessor.isNodeExclusionAvailable((T)n)) return true;
|
||||
if (Boolean.valueOf(myIsExclude) != exclusionProcessor.isNodeExcluded((T)n)) {
|
||||
if (myIsExclude != exclusionProcessor.isNodeExcluded((T)n)) {
|
||||
if (myIsExclude) {
|
||||
exclusionProcessor.excludeNode(node);
|
||||
} else {
|
||||
|
||||
+6
-9
@@ -22,10 +22,10 @@ import com.intellij.openapi.wm.ToolWindowId;
|
||||
import org.fest.swing.core.Robot;
|
||||
import org.fest.swing.edt.GuiQuery;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.fest.swing.edt.GuiActionRunner.execute;
|
||||
@@ -47,10 +47,10 @@ public class InspectionsFixture extends ToolWindowFixture {
|
||||
|
||||
return execute(new GuiQuery<String>() {
|
||||
@Override
|
||||
@Nullable
|
||||
protected String executeInEDT() throws Throwable {
|
||||
@NotNull
|
||||
protected String executeInEDT() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
InspectionsFixture.describe(myTree.getRoot(), sb, 0);
|
||||
describe(myTree.getInspectionTreeModel().getRoot(), sb, 0);
|
||||
return sb.toString();
|
||||
}
|
||||
});
|
||||
@@ -65,11 +65,8 @@ public class InspectionsFixture extends ToolWindowFixture {
|
||||
|
||||
// The exact order of the results sometimes varies so sort the children alphabetically
|
||||
// instead to ensure stable test output
|
||||
List<InspectionTreeNode> children = new ArrayList<>(node.getChildCount());
|
||||
for (int i = 0, n = node.getChildCount(); i < n; i++) {
|
||||
children.add((InspectionTreeNode)node.getChildAt(i));
|
||||
}
|
||||
Collections.sort(children, (node1, node2) -> node1.toString().compareTo(node2.toString()));
|
||||
List<InspectionTreeNode> children = new ArrayList<>(node.getChildren());
|
||||
Collections.sort(children, Comparator.comparing(Object::toString));
|
||||
for (InspectionTreeNode child : children) {
|
||||
describe(child, sb, depth + 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user