inspection tool window: do not update tree in EDT (offline inspection view freeze). not polished

This commit is contained in:
Dmitry Batkovich
2016-02-26 15:56:27 +03:00
parent 2bd4db6f55
commit 06e337a73f
19 changed files with 346 additions and 270 deletions

View File

@@ -54,7 +54,7 @@ public class OfflineIRVTest extends TestSourceBasedTestCase {
private LocalInspectionToolWrapper myToolWrapper;
private static String varMessage(String name) {
return InspectionsBundle.message("inspection.unused.assignment.problem.descriptor1", "<code>"+name+"</code>") + ".";
return InspectionsBundle.message("inspection.unused.assignment.problem.descriptor1", "'" + name + "'");
}
@Override
@@ -146,7 +146,7 @@ public class OfflineIRVTest extends TestSourceBasedTestCase {
+ " -f()\n"
+ " -D\n"
+ " -b()\n"
+ " " + InspectionsBundle.message("inspection.unused.assignment.problem.descriptor1", "'" + "r" + "'") + "\n"
+ " " + varMessage("r") + "\n"
+ " -anonymous (java.lang.Runnable)\n"
+ " -run()\n"
+ " " + varMessage("i") + "\n"

View File

@@ -23,9 +23,12 @@ package com.intellij.codeInspection.offline;
import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.reference.RefManager;
import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
@@ -112,7 +115,7 @@ public class OfflineProblemDescriptor {
if (refElement instanceof RefElement) {
final PsiElement element = ((RefElement)refElement).getElement();
if (element != null && element.isValid()) {
PsiDocumentManager.getInstance(element.getProject()).commitAllDocuments();
UIUtil.invokeLaterIfNeeded(() -> PsiDocumentManager.getInstance(element.getProject()).commitAllDocuments());
}
}
return refElement;
@@ -178,6 +181,10 @@ public class OfflineProblemDescriptor {
@Override
public String toString() {
return myDescription;
if (ApplicationManager.getApplication().isUnitTestMode()) {
return myFQName;
} else {
return myDescription;
}
}
}

View File

@@ -225,7 +225,9 @@ public class ViewOfflineResultsAction extends AnAction {
final InspectionResultsView view = new InspectionResultsView(context,
new OfflineInspectionRVContentProvider(resMap, project));
((RefManagerImpl)context.getRefManager()).startOfflineView();
view.update();
ApplicationManager.getApplication().executeOnPooledThread(() -> {
ApplicationManager.getApplication().runReadAction((Runnable)view::buildTree);
});
TreeUtil.selectFirstNode(view.getTree());
context.addView(view, title);
return view;

View File

@@ -125,6 +125,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
});
myView = view;
myView.getTree().setPaintBusy(true);
myContent = ContentFactory.SERVICE.getInstance().createContent(view, title, false);
myContent.setDisposer(myView);
@@ -353,6 +354,9 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
else if (view != null) {
addView(view);
}
if (myView != null) {
myView.getTree().setPaintBusy(false);
}
}
});
}

View File

@@ -20,6 +20,7 @@
*/
package com.intellij.codeInspection.ex;
import com.google.common.collect.Multimap;
import com.intellij.codeInspection.CommonProblemDescriptor;
import com.intellij.codeInspection.QuickFix;
import com.intellij.codeInspection.reference.RefEntity;
@@ -31,6 +32,7 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.util.Function;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,6 +42,7 @@ import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.util.*;
import java.util.function.Consumer;
public abstract class InspectionRVContentProvider {
private static final Logger LOG = Logger.getInstance("#" + InspectionRVContentProvider.class.getName());
@@ -121,22 +124,23 @@ public abstract class InspectionRVContentProvider {
protected abstract void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
@NotNull InspectionToolWrapper toolWrapper,
@NotNull UserObjectContainer container,
@NotNull InspectionPackageNode pNode,
@NotNull InspectionTreeNode pNode,
final boolean canPackageRepeat);
public boolean isContentLoaded() {
return true;
}
protected <T> List<InspectionTreeNode> buildTree(@NotNull GlobalInspectionContextImpl context,
@NotNull Map<String, Set<T>> packageContents,
final boolean canPackageRepeat,
@NotNull InspectionToolWrapper toolWrapper,
@NotNull Function<T, UserObjectContainer<T>> computeContainer,
final boolean showStructure) {
final List<InspectionTreeNode> content = new ArrayList<InspectionTreeNode>();
protected <T> void buildTree(@NotNull GlobalInspectionContextImpl context,
@NotNull Map<String, Set<T>> packageContents,
final boolean canPackageRepeat,
@NotNull InspectionToolWrapper toolWrapper,
@NotNull Function<T, UserObjectContainer<T>> computeContainer,
final boolean showStructure,
final Consumer<InspectionTreeNode> createdNodesConsumer) {
final Map<String, Map<String, InspectionPackageNode>> module2PackageMap = new HashMap<String, Map<String, InspectionPackageNode>>();
boolean supportStructure = showStructure;
final MultiMap<InspectionPackageNode, UserObjectContainer<T>> packageDescriptors = new MultiMap<>();
for (String packageName : packageContents.keySet()) {
final Set<T> elements = packageContents.get(packageName);
for (T userObject : elements) {
@@ -153,50 +157,64 @@ public abstract class InspectionRVContentProvider {
pNode = new InspectionPackageNode(packageName);
packageNodes.put(packageName, pNode);
}
appendDescriptor(context, toolWrapper, container, pNode, canPackageRepeat);
packageDescriptors.putValue(pNode, container);
}
}
if (supportStructure) {
final HashMap<String, InspectionModuleNode> moduleNodes = new HashMap<String, InspectionModuleNode>();
for (final String moduleName : module2PackageMap.keySet()) {
final Map<String, InspectionPackageNode> packageNodes = module2PackageMap.get(moduleName);
for (InspectionPackageNode packageNode : packageNodes.values()) {
if (packageNode.getChildCount() > 0) {
InspectionModuleNode moduleNode = moduleNodes.get(moduleName);
if (moduleNode == null) {
if (moduleName != null) {
final Module module = ModuleManager.getInstance(myProject).findModuleByName(moduleName);
if (module != null) {
moduleNode = new InspectionModuleNode(module);
moduleNodes.put(moduleName, moduleNode);
}
else { //module content was removed ?
continue;
}
} else {
content.addAll(packageNodes.values());
break;
InspectionModuleNode moduleNode = moduleNodes.get(moduleName);
if (moduleNode == null) {
if (moduleName != null) {
final Module module = ModuleManager.getInstance(myProject).findModuleByName(moduleName);
if (module != null) {
moduleNode = new InspectionModuleNode(module);
moduleNodes.put(moduleName, moduleNode);
}
else { //module content was removed ?
continue;
}
}
else {
for (InspectionPackageNode packageNode : packageNodes.values()) {
createdNodesConsumer.accept(packageNode);
for (UserObjectContainer<T> container : packageDescriptors.get(packageNode)) {
appendDescriptor(context, toolWrapper, container, packageNode, canPackageRepeat);
}
}
if (packageNode.getPackageName() != null) {
moduleNode.add(packageNode);
} else {
for(int i = packageNode.getChildCount() - 1; i >= 0; i--) {
moduleNode.add((MutableTreeNode)packageNode.getChildAt(i));
}
continue;
}
}
createdNodesConsumer.accept(moduleNode);
for (InspectionPackageNode packageNode : packageNodes.values()) {
if (packageNode.getPackageName() != null) {
moduleNode.add(packageNode);
for (UserObjectContainer<T> container : packageDescriptors.get(packageNode)) {
appendDescriptor(context, toolWrapper, container, packageNode, canPackageRepeat);
}
}
else {
for (UserObjectContainer<T> container : packageDescriptors.get(packageNode)) {
appendDescriptor(context, toolWrapper, container, moduleNode, canPackageRepeat);
}
}
}
}
content.addAll(moduleNodes.values());
}
else {
for (Map<String, InspectionPackageNode> packageNodes : module2PackageMap.values()) {
for (InspectionPackageNode pNode : packageNodes.values()) {
for (UserObjectContainer<T> container : packageDescriptors.get(pNode)) {
appendDescriptor(context, toolWrapper, container, pNode, canPackageRepeat);
}
for (int i = 0; i < pNode.getChildCount(); i++) {
final TreeNode childNode = pNode.getChildAt(i);
if (childNode instanceof ProblemDescriptionNode) {
content.add(pNode);
createdNodesConsumer.accept(pNode);
break;
}
LOG.assertTrue(childNode instanceof RefElementNode, childNode.getClass().getName());
@@ -216,7 +234,7 @@ public abstract class InspectionRVContentProvider {
parentNodes.add((RefElementNode)grandChildNode);
}
if (!hasElementNodeUnder) {
content.add(elementNode);
createdNodesConsumer.accept(elementNode);
continue;
}
}
@@ -237,12 +255,13 @@ public abstract class InspectionRVContentProvider {
parentNode.add(node);
}
}
content.addAll(parentNodes);
for (RefElementNode node : parentNodes) {
createdNodesConsumer.accept(node);
}
}
}
}
}
return content;
}
@NotNull
@@ -333,19 +352,11 @@ public abstract class InspectionRVContentProvider {
}
protected static void add(@Nullable final DefaultTreeModel model, final InspectionTreeNode child, final InspectionTreeNode parent) {
if (model == null) {
insertByIndex(child, parent);
}
else {
if (parent.getIndex(child) < 0) {
model.insertNodeInto(child, parent, child.getParent() == parent ? parent.getChildCount() - 1 : parent.getChildCount());
}
}
insertByIndex(child, parent);
}
private static void insertByIndex(InspectionTreeNode child, InspectionTreeNode parent) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
parent.add(child);
public static void insertByIndex(InspectionTreeNode child, InspectionTreeNode parent) {
if (parent.getIndex(child) != -1) {
return;
}
final int i = TreeUtil.indexedBinarySearch(parent, child, InspectionResultsViewComparator.getInstance());

View File

@@ -95,7 +95,6 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
@NotNull final Map<String, Set<RefEntity>> contents,
@NotNull final Map<RefEntity, CommonProblemDescriptor[]> problems,
DefaultTreeModel model) {
ApplicationManager.getApplication().assertIsDispatchThread();
final InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
Function<RefEntity, UserObjectContainer<RefEntity>> computeContainer = new Function<RefEntity, UserObjectContainer<RefEntity>>() {
@@ -114,11 +113,9 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
}
entities.addAll(moduleProblems);
}
List<InspectionTreeNode> list = buildTree(context, contents, false, toolWrapper, computeContainer, showStructure);
for (InspectionTreeNode node : list) {
buildTree(context, contents, false, toolWrapper, computeContainer, showStructure, node -> {
merge(model, node, toolNode, true);
}
});
if (presentation.isOldProblemsIncluded()) {
final Map<RefEntity, CommonProblemDescriptor[]> oldProblems = presentation.getOldProblemElements();
@@ -129,11 +126,9 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
}
};
list = buildTree(context, presentation.getOldContent(), true, toolWrapper, computeContainer, showStructure);
for (InspectionTreeNode node : list) {
buildTree(context, presentation.getOldContent(), true, toolWrapper, computeContainer, showStructure, node -> {
merge(model, node, toolNode, true);
}
});
}
merge(model, toolNode, parentNode, false);
}
@@ -142,7 +137,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
protected void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
@NotNull final InspectionToolWrapper toolWrapper,
@NotNull final UserObjectContainer container,
@NotNull final InspectionPackageNode pNode,
@NotNull final InspectionTreeNode pNode,
final boolean canPackageRepeat) {
final RefElementContainer refElementDescriptor = (RefElementContainer)container;
final RefEntity refElement = refElementDescriptor.getUserObject();
@@ -163,8 +158,8 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
}
}
else {
if (canPackageRepeat) {
final Set<RefEntity> currentElements = presentation.getContent().get(pNode.getPackageName());
if (canPackageRepeat && pNode instanceof InspectionPackageNode) {
final Set<RefEntity> currentElements = presentation.getContent().get(((InspectionPackageNode) pNode).getPackageName());
if (currentElements != null) {
final Set<RefEntity> currentEntities = new HashSet<RefEntity>(currentElements);
if (RefUtil.contains(refElement, currentEntities)) return;

View File

@@ -125,11 +125,8 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
return new OfflineProblemDescriptorContainer(descriptor);
}
};
final List<InspectionTreeNode> list = buildTree(context, filteredContent, false, toolWrapper, computeContainer, showStructure);
for (InspectionTreeNode node : list) {
toolNode.add(node);
}
parentNode.add(toolNode);
buildTree(context, filteredContent, false, toolWrapper, computeContainer, showStructure, toolNode::add);
}
}
@@ -175,13 +172,15 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
protected void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
@NotNull final InspectionToolWrapper toolWrapper,
@NotNull final UserObjectContainer container,
@NotNull final InspectionPackageNode packageNode,
@NotNull final InspectionTreeNode packageNode,
final boolean canPackageRepeat) {
InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
final RefElementNode elemNode = addNodeToParent(container, presentation, packageNode);
if (toolWrapper instanceof LocalInspectionToolWrapper) {
elemNode.add(new OfflineProblemDescriptorNode(((OfflineProblemDescriptorContainer)container).getUserObject(),
(LocalInspectionToolWrapper)toolWrapper, presentation));
final OfflineProblemDescriptorNode child =
OfflineProblemDescriptorNode.create(((OfflineProblemDescriptorContainer)container).getUserObject(),
(LocalInspectionToolWrapper)toolWrapper, presentation);
insertByIndex(child, elemNode);
}
}

View File

@@ -47,10 +47,33 @@ import java.util.List;
import java.util.Set;
public class OfflineProblemDescriptorNode extends ProblemDescriptionNode {
OfflineProblemDescriptorNode(@NotNull OfflineProblemDescriptor descriptor,
OfflineProblemDescriptorNode(RefEntity refEntity,
CommonProblemDescriptor descriptor,
@NotNull LocalInspectionToolWrapper toolWrapper,
@NotNull InspectionToolPresentation presentation) {
super(descriptor, toolWrapper, presentation);
@NotNull InspectionToolPresentation presentation,
OfflineProblemDescriptor offlineDescriptor) {
super(refEntity, descriptor, toolWrapper, presentation);
if (descriptor == null) {
setUserObject(offlineDescriptor);
}
}
static OfflineProblemDescriptorNode create(@NotNull OfflineProblemDescriptor offlineDescriptor,
@NotNull LocalInspectionToolWrapper toolWrapper,
@NotNull InspectionToolPresentation presentation) {
final RefEntity refElement = createRefElement(offlineDescriptor, presentation);
final CommonProblemDescriptor descriptor = createDescriptor(refElement, offlineDescriptor, toolWrapper, presentation);
return new OfflineProblemDescriptorNode(refElement, descriptor, toolWrapper, presentation, offlineDescriptor);
}
@Override
public boolean isValid() {
return true;
}
@Override
public FileStatus getNodeStatus() {
return FileStatus.NOT_CHANGED;
}
private static PsiElement[] getElementsIntersectingRange(PsiFile file, final int startOffset, final int endOffset) {
@@ -65,77 +88,49 @@ public class OfflineProblemDescriptorNode extends ProblemDescriptionNode {
return PsiUtilCore.toPsiElementArray(result);
}
@Override
@Nullable
public RefEntity getElement() {
if (userObject instanceof CommonProblemDescriptor) {
return myElement;
}
if (userObject == null) {
return null;
}
myElement = ((OfflineProblemDescriptor)userObject).getRefElement(myPresentation.getContext().getRefManager());
return myElement;
private static RefEntity createRefElement(OfflineProblemDescriptor descriptor, InspectionToolPresentation presentation) {
return descriptor.getRefElement(presentation.getContext().getRefManager());
}
@Override
@Nullable
public CommonProblemDescriptor getDescriptor() {
if (userObject == null) return null;
if (userObject instanceof CommonProblemDescriptor) {
return (CommonProblemDescriptor)userObject;
}
private static CommonProblemDescriptor createDescriptor(@Nullable RefEntity element,
@NotNull OfflineProblemDescriptor offlineDescriptor,
@NotNull LocalInspectionToolWrapper toolWrapper,
@NotNull InspectionToolPresentation presentation) {
final InspectionManager inspectionManager = InspectionManager.getInstance(myPresentation.getContext().getProject());
final OfflineProblemDescriptor offlineProblemDescriptor = (OfflineProblemDescriptor)userObject;
final RefEntity element = getElement();
if (myToolWrapper instanceof LocalInspectionToolWrapper) {
if (element instanceof RefElement) {
final PsiElement psiElement = ((RefElement)element).getElement();
if (psiElement != null) {
ProblemDescriptor descriptor = ProgressManager.getInstance().runProcess(new Computable<ProblemDescriptor>() {
@Override
public ProblemDescriptor compute() {
return runLocalTool(psiElement, inspectionManager, offlineProblemDescriptor);
}
}, new DaemonProgressIndicator());
if (descriptor != null) return descriptor;
}
final InspectionManager inspectionManager = InspectionManager.getInstance(presentation.getContext().getProject());
final OfflineProblemDescriptor offlineProblemDescriptor = offlineDescriptor;
if (element instanceof RefElement) {
final PsiElement psiElement = ((RefElement)element).getElement();
if (psiElement != null) {
ProblemDescriptor descriptor = ProgressManager.getInstance().runProcess(new Computable<ProblemDescriptor>() {
@Override
public ProblemDescriptor compute() {
return runLocalTool(psiElement, inspectionManager, offlineProblemDescriptor, toolWrapper);
}
}, new DaemonProgressIndicator());
if (descriptor != null) return descriptor;
}
setUserObject(null);
return null;
}
final List<String> hints = offlineProblemDescriptor.getHints();
if (element instanceof RefElement) {
final PsiElement psiElement = ((RefElement)element).getElement();
if (psiElement == null) return null;
ProblemDescriptor descriptor = inspectionManager.createProblemDescriptor(psiElement, offlineProblemDescriptor.getDescription(),
(LocalQuickFix)null,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false);
final LocalQuickFix[] quickFixes = getFixes(descriptor, hints);
if (quickFixes != null) {
descriptor = inspectionManager.createProblemDescriptor(psiElement, offlineProblemDescriptor.getDescription(), false, quickFixes,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
setUserObject(descriptor);
return descriptor;
}
CommonProblemDescriptor descriptor =
inspectionManager.createProblemDescriptor(offlineProblemDescriptor.getDescription(), (QuickFix)null);
final QuickFix[] quickFixes = getFixes(descriptor, hints);
final QuickFix[] quickFixes = getFixes(descriptor, hints, presentation);
if (quickFixes != null) {
descriptor = inspectionManager.createProblemDescriptor(offlineProblemDescriptor.getDescription(), quickFixes);
}
setUserObject(descriptor);
return descriptor;
}
private ProblemDescriptor runLocalTool(@NotNull PsiElement psiElement,
@NotNull InspectionManager inspectionManager,
@NotNull OfflineProblemDescriptor offlineProblemDescriptor) {
private static ProblemDescriptor runLocalTool(@NotNull PsiElement psiElement,
@NotNull InspectionManager inspectionManager,
@NotNull OfflineProblemDescriptor offlineProblemDescriptor,
@NotNull LocalInspectionToolWrapper toolWrapper) {
PsiFile containingFile = psiElement.getContainingFile();
final ProblemsHolder holder = new ProblemsHolder(inspectionManager, containingFile, false);
final LocalInspectionTool localTool = ((LocalInspectionToolWrapper)myToolWrapper).getTool();
final LocalInspectionTool localTool = toolWrapper.getTool();
final int startOffset = psiElement.getTextRange().getStartOffset();
final int endOffset = psiElement.getTextRange().getEndOffset();
LocalInspectionToolSession session = new LocalInspectionToolSession(containingFile, startOffset, endOffset);
@@ -154,7 +149,6 @@ public class OfflineProblemDescriptorNode extends ProblemDescriptionNode {
final PsiNamedElement member = localTool.getProblemElement(descriptor.getPsiElement());
if (psiElement instanceof PsiFile || member != null && member.equals(psiElement)) {
if (curIdx == idx) {
setUserObject(descriptor);
return descriptor;
}
curIdx++;
@@ -166,40 +160,24 @@ public class OfflineProblemDescriptorNode extends ProblemDescriptionNode {
}
@Nullable
private LocalQuickFix[] getFixes(@NotNull CommonProblemDescriptor descriptor, List<String> hints) {
private static LocalQuickFix[] getFixes(@NotNull CommonProblemDescriptor descriptor, List<String> hints, InspectionToolPresentation presentation) {
final List<LocalQuickFix> fixes = new ArrayList<LocalQuickFix>(hints == null ? 1 : hints.size());
if (hints == null) {
addFix(descriptor, fixes, null);
addFix(descriptor, fixes, null, presentation);
}
else {
for (String hint : hints) {
addFix(descriptor, fixes, hint);
addFix(descriptor, fixes, hint, presentation);
}
}
return fixes.isEmpty() ? null : fixes.toArray(new LocalQuickFix[fixes.size()]);
}
private void addFix(@NotNull CommonProblemDescriptor descriptor, final List<LocalQuickFix> fixes, String hint) {
final IntentionAction intentionAction = myPresentation.findQuickFixes(descriptor, hint);
private static void addFix(@NotNull CommonProblemDescriptor descriptor, final List<LocalQuickFix> fixes, String hint, InspectionToolPresentation presentation) {
final IntentionAction intentionAction = presentation.findQuickFixes(descriptor, hint);
if (intentionAction instanceof QuickFixWrapper) {
fixes.add(((QuickFixWrapper)intentionAction).getFix());
}
}
@Override
public boolean isValid() {
return true;
}
@Override
public FileStatus getNodeStatus() {
return FileStatus.NOT_CHANGED;
}
public String toString() {
if (userObject instanceof OfflineProblemDescriptor) {
return ((OfflineProblemDescriptor)userObject).getDescription();
}
return super.toString();
}
}

View File

@@ -28,27 +28,17 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OfflineRefElementNode extends RefElementNode {
private final RefEntity myElement;
public OfflineRefElementNode(@NotNull OfflineProblemDescriptor descriptor, @NotNull InspectionToolPresentation presentation) {
super(descriptor, presentation);
myElement = descriptor.getRefElement(presentation.getContext().getRefManager());
}
@Override
@Nullable
public RefEntity getElement() {
if (userObject instanceof RefEntity) {
return (RefEntity)userObject;
}
if (userObject == null) return null;
final RefEntity refElement = ((OfflineProblemDescriptor)userObject).getRefElement(myToolPresentation.getContext().getRefManager());
setUserObject(refElement);
return refElement;
}
@Nullable
public OfflineProblemDescriptor getDescriptor() {
if (userObject instanceof OfflineProblemDescriptor) {
return (OfflineProblemDescriptor)userObject;
}
return null;
setUserObject(myElement);
return myElement;
}
}

View File

@@ -24,6 +24,7 @@ import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ex.*;
import com.intellij.codeInspection.reference.*;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -78,8 +79,6 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
protected static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.DescriptorProviderInspection");
private boolean isDisposed;
private final Object myToolLock = new Object();
public DefaultInspectionToolPresentation(@NotNull InspectionToolWrapper toolWrapper, @NotNull GlobalInspectionContextImpl context) {
myToolWrapper = toolWrapper;
myContext = context;
@@ -237,33 +236,33 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
context.addView(view);
}
if (!isDisposed()) {
final InspectionNode toolNode;
synchronized (myToolLock) {
if (myToolNode == null) {
final HighlightSeverity currentSeverity = getSeverity((RefElement)refElement);
toolNode = view.addTool(myToolWrapper, HighlightDisplayLevel.find(currentSeverity), context.getUIOptions().GROUP_BY_SEVERITY);
}
else {
toolNode = myToolNode;
if (toolNode.isTooBigForOnlineRefresh()) {
return;
}
}
}
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<RefEntity, CommonProblemDescriptor[]>();
problems.put(refElement, descriptors);
final Map<String, Set<RefEntity>> contents = new HashMap<String, Set<RefEntity>>();
final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement);
Set<RefEntity> content = contents.get(groupName);
if (content == null) {
content = new HashSet<RefEntity>();
contents.put(groupName, content);
}
content.add(refElement);
final InspectionResultsView finalView = view;
ApplicationManager.getApplication().executeOnPooledThread(() -> {
ApplicationManager.getApplication().runReadAction(() -> {
synchronized (finalView.getTreeWriteLock()) {
final InspectionNode toolNode;
toolNode = myToolNode == null ?
finalView.addTool(myToolWrapper, HighlightDisplayLevel.find(getSeverity((RefElement)refElement)),
context.getUIOptions().GROUP_BY_SEVERITY) : myToolNode;
view.getProvider().appendToolNodeContent(context, toolNode,
(InspectionTreeNode)toolNode.getParent(), context.getUIOptions().SHOW_STRUCTURE,
contents, problems, (DefaultTreeModel)view.getTree().getModel());
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<RefEntity, CommonProblemDescriptor[]>();
problems.put(refElement, descriptors);
final Map<String, Set<RefEntity>> contents = new HashMap<String, Set<RefEntity>>();
final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement);
Set<RefEntity> content = contents.get(groupName);
if (content == null) {
content = new HashSet<RefEntity>();
contents.put(groupName, content);
}
content.add(refElement);
finalView.getProvider().appendToolNodeContent(context, toolNode,
(InspectionTreeNode)toolNode.getParent(), context.getUIOptions().SHOW_STRUCTURE,
contents, problems, (DefaultTreeModel)finalView.getTree().getModel());
}
});
});
}
}
});
@@ -303,11 +302,8 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
return Arrays.copyOfRange(out, 0, o);
}
public void setToolNode(InspectionNode toolNode) {
synchronized (myToolLock) {
myToolNode = toolNode;
}
myToolNode = toolNode;
}
protected boolean isDisposed() {

View File

@@ -25,7 +25,7 @@ import javax.swing.*;
/**
* @author max
*/
class InspectionGroupNode extends InspectionTreeNode {
public class InspectionGroupNode extends InspectionTreeNode {
private static final Icon EMPTY = new EmptyIcon(0, IconUtil.getEmptyIcon(false).getIconHeight());
InspectionGroupNode(@NotNull String groupTitle) {

View File

@@ -29,7 +29,7 @@ import javax.swing.*;
*/
public class InspectionNode extends InspectionTreeNode {
public static final Icon TOOL = LayeredIcon.create(AllIcons.Toolwindows.ToolWindowInspection, IconUtil.getEmptyIcon(false));
private boolean myTooBigForOnlineRefresh = false;
private volatile boolean myUpdatingNow;
public InspectionNode(@NotNull InspectionToolWrapper toolWrapper) {
super(toolWrapper);
@@ -49,10 +49,4 @@ public class InspectionNode extends InspectionTreeNode {
return TOOL;
}
public boolean isTooBigForOnlineRefresh() {
if (!myTooBigForOnlineRefresh) {
myTooBigForOnlineRefresh = getProblemCount() > 1000;
}
return myTooBigForOnlineRefresh;
}
}

View File

@@ -50,23 +50,26 @@ import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.pom.Navigatable;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.*;
import com.intellij.ui.components.JBLabel;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.impl.UsagePreviewPanel;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.OpenSourceUtil;
import com.intellij.util.containers.*;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
@@ -76,10 +79,11 @@ import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import static com.intellij.codeInspection.ex.InspectionRVContentProvider.insertByIndex;
/**
* @author max
*/
@@ -112,6 +116,8 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
private AnAction myExcludeAction;
private Editor myPreviewEditor;
private final Object myTreeWriteLock = new Object();
public InspectionResultsView(@NotNull GlobalInspectionContextImpl globalInspectionContext,
@NotNull InspectionRVContentProvider provider) {
setLayout(new BorderLayout());
@@ -144,10 +150,14 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
private void initTreeListeners() {
myTree.getSelectionModel().addTreeSelectionListener(e -> {
syncRightPanel();
if (isAutoScrollMode()) {
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false);
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
if (myTree.isUnderQueueUpdate()) return;
syncRightPanel();
if (isAutoScrollMode()) {
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false);
}
}
});
@@ -509,8 +519,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
myProvider.appendToolNodeContent(myGlobalInspectionContext, toolNode, parentNode, showStructure);
InspectionToolPresentation presentation = myGlobalInspectionContext.getPresentation(toolWrapper);
toolNode = presentation.createToolNode(myGlobalInspectionContext, toolNode, myProvider, parentNode, showStructure);
((DefaultInspectionToolPresentation)presentation).setToolNode(toolNode);
synchronized (myTreeWriteLock) {
((DefaultInspectionToolPresentation)presentation).setToolNode(toolNode);
}
registerActionShortcuts(presentation);
return toolNode;
}
@@ -553,24 +564,31 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
return resultsFound;
}
private boolean buildTree() {
InspectionProfile profile = myInspectionProfile;
boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY;
myGroups.clear();
final Map<String, Tools> tools = myGlobalInspectionContext.getTools();
boolean resultsFound = false;
for (Tools currentTools : tools.values()) {
InspectionToolWrapper defaultToolWrapper = currentTools.getDefaultState().getTool();
final HighlightDisplayKey key = HighlightDisplayKey.find(defaultToolWrapper.getShortName());
for (ScopeToolState state : myProvider.getTools(currentTools)) {
InspectionToolWrapper toolWrapper = state.getTool();
if (myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper)) {
addTool(toolWrapper, ((InspectionProfileImpl)profile).getErrorLevel(key, state.getScope(myProject), myProject), isGroupedBySeverity);
resultsFound = true;
public Object getTreeWriteLock() {
return myTreeWriteLock;
}
public boolean buildTree() {
synchronized (myTreeWriteLock) {
InspectionProfile profile = myInspectionProfile;
boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY;
myGroups.clear();
final Map<String, Tools> tools = myGlobalInspectionContext.getTools();
boolean resultsFound = false;
for (Tools currentTools : tools.values()) {
InspectionToolWrapper defaultToolWrapper = currentTools.getDefaultState().getTool();
final HighlightDisplayKey key = HighlightDisplayKey.find(defaultToolWrapper.getShortName());
for (ScopeToolState state : myProvider.getTools(currentTools)) {
InspectionToolWrapper toolWrapper = state.getTool();
if (myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper)) {
addTool(toolWrapper, ((InspectionProfileImpl)profile).getErrorLevel(key, state.getScope(myProject), myProject),
isGroupedBySeverity);
resultsFound = true;
}
}
}
return resultsFound;
}
return resultsFound;
}
@NotNull
@@ -594,7 +612,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
}
if (group == null) {
group = ConcurrencyUtil.cacheOrGet(map, groupName, new InspectionGroupNode(groupName));
addChildNodeInEDT(getRelativeRootNode(groupedBySeverity, errorLevel), group);
if (!myDisposed) {
insertByIndex(group, getRelativeRootNode(groupedBySeverity, errorLevel));
}
}
return group;
}
@@ -608,7 +628,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
severityGroupNode = ConcurrencyUtil.cacheOrGet(mySeverityGroupNodes, level, newNode);
if (severityGroupNode == newNode) {
InspectionTreeNode root = myTree.getRoot();
addChildNodeInEDT(root, severityGroupNode);
insertByIndex(root, severityGroupNode);
}
}
return severityGroupNode;
@@ -616,18 +636,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
return myTree.getRoot();
}
private void addChildNodeInEDT(@NotNull final DefaultMutableTreeNode root, @NotNull final MutableTreeNode severityGroupNode) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if (!myDisposed) {
root.add(severityGroupNode);
}
}
});
}
private OccurenceNavigator getOccurenceNavigator() {
return myOccurenceNavigator;
}

View File

@@ -22,8 +22,10 @@ import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.util.PlatformUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.MutableTreeNode;
/**
* @author max
@@ -34,9 +36,10 @@ public class InspectionRootNode extends InspectionTreeNode {
: IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getSmallIconUrl());
private final Project myProject;
public InspectionRootNode(Project project) {
public InspectionRootNode(Project project, @NotNull InspectionTreeUpdater updater) {
super(project);
myProject = project;
myUpdater = updater;
}
public String toString() {
@@ -52,4 +55,9 @@ public class InspectionRootNode extends InspectionTreeNode {
public Icon getIcon(boolean expanded) {
return APP_ICON;
}
@Override
public void add(MutableTreeNode newChild) {
super.add(newChild);
}
}

View File

@@ -40,15 +40,13 @@ import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeModelAdapter;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.event.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeNode;
@@ -59,9 +57,10 @@ public class InspectionTree extends Tree {
private final HashSet<Object> myExpandedUserObjects;
@NotNull private final GlobalInspectionContextImpl myContext;
private SelectionPath mySelectionPath;
private boolean myQueueUpdate;
public InspectionTree(@NotNull Project project, @NotNull GlobalInspectionContextImpl context) {
super(new InspectionRootNode(project));
setModel(new DefaultTreeModel(new InspectionRootNode(project, new InspectionTreeUpdater(this))));
myContext = context;
setCellRenderer(new CellRenderer());
@@ -91,6 +90,14 @@ public class InspectionTree extends Tree {
});
}
public void setQueueUpdate(boolean queueUpdate) {
myQueueUpdate = queueUpdate;
}
public boolean isUnderQueueUpdate() {
return myQueueUpdate;
}
public void removeAllNodes() {
getRoot().removeAllChildren();
nodeStructureChanged(getRoot());
@@ -297,9 +304,9 @@ public class InspectionTree extends Tree {
}
}
private void restoreExpansionStatus(InspectionTreeNode node) {
public void restoreExpansionStatus(InspectionTreeNode node) {
if (myExpandedUserObjects.contains(node.getUserObject())) {
sortChildren(node);
//sortChildren(node);
TreeNode[] pathToNode = node.getPath();
expandPath(new TreePath(pathToNode));
Enumeration children = node.children();

View File

@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import java.util.Enumeration;
/**
@@ -28,6 +29,7 @@ import java.util.Enumeration;
*/
public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
private boolean myResolved;
protected volatile InspectionTreeUpdater myUpdater;
protected InspectionTreeNode(Object userObject) {
super(userObject);
}
@@ -78,4 +80,33 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode {
child.amnesty();
}
}
@Override
public void add(MutableTreeNode newChild) {
super.add(newChild);
if (myUpdater != null) {
((InspectionTreeNode)newChild).propagateUpdater(myUpdater);
myUpdater.update();
}
}
@Override
public void insert(MutableTreeNode newChild, int childIndex) {
super.insert(newChild, childIndex);
if (myUpdater != null) {
((InspectionTreeNode)newChild).propagateUpdater(myUpdater);
myUpdater.update();
}
}
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);
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.openapi.application.ApplicationManager;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import javax.swing.tree.DefaultTreeModel;
/**
* @author Dmitry Batkovich
*/
public class InspectionTreeUpdater {
private final InspectionTree myTree;
private final MergingUpdateQueue myUpdateQueue;
public InspectionTreeUpdater(InspectionTree tree) {
myTree = tree;
myUpdateQueue = new MergingUpdateQueue("InspectionView", 100, true, tree);
}
public void update() {
if (ApplicationManager.getApplication().isDispatchThread()) {
return;
}
myUpdateQueue.queue(new Update("TreeRepaint") {
@Override
public void run() {
try {
myTree.setQueueUpdate(true);
((DefaultTreeModel)myTree.getModel()).reload();
myTree.revalidate();
myTree.repaint();
myTree.restoreExpansionAndSelection();
} finally {
myTree.setQueueUpdate(false);
}
}
@Override
public boolean canEat(Update update) {
return true;
}
});
}
}

View File

@@ -38,32 +38,18 @@ import static com.intellij.codeInspection.ProblemDescriptorUtil.TRIM_AT_TREE_END
public class ProblemDescriptionNode extends InspectionTreeNode {
protected RefEntity myElement;
private final CommonProblemDescriptor myDescriptor;
protected final InspectionToolWrapper myToolWrapper;
protected final InspectionToolWrapper toolWrapper;
@NotNull
protected final InspectionToolPresentation myPresentation;
public ProblemDescriptionNode(@NotNull Object userObject,
@NotNull InspectionToolWrapper toolWrapper,
@NotNull InspectionToolPresentation presentation) {
this(userObject, null, null, toolWrapper, presentation);
}
public ProblemDescriptionNode(@NotNull RefEntity element,
@NotNull CommonProblemDescriptor descriptor,
@NotNull InspectionToolWrapper toolWrapper,
@NotNull InspectionToolPresentation presentation) {
this(descriptor, element, descriptor, toolWrapper, presentation);
}
private ProblemDescriptionNode(@NotNull Object userObject,
RefEntity element,
public ProblemDescriptionNode(RefEntity element,
CommonProblemDescriptor descriptor,
@NotNull InspectionToolWrapper toolWrapper,
@NotNull InspectionToolPresentation presentation) {
super(userObject);
super(descriptor);
myElement = element;
myDescriptor = descriptor;
myToolWrapper = toolWrapper;
this.toolWrapper = toolWrapper;
myPresentation = presentation;
}

View File

@@ -47,7 +47,7 @@ public class RefElementNode extends InspectionTreeNode {
}
});
public RefElementNode(@NotNull Object userObject, @NotNull InspectionToolPresentation presentation) {
public RefElementNode(@Nullable Object userObject, @NotNull InspectionToolPresentation presentation) {
super(userObject);
myToolPresentation = presentation;
}