mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
inspection view: get rid of global lock in presentation
This commit is contained in:
+14
-21
@@ -78,7 +78,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class UnusedDeclarationPresentation extends DefaultInspectionToolPresentation {
|
||||
|
||||
private final Set<RefEntity> myIgnoreElements = ConcurrentCollectionFactory.createConcurrentSet(ContainerUtil.identityStrategy());
|
||||
private final Set<RefEntity> myResolvedElements = ConcurrentCollectionFactory.createConcurrentSet(ContainerUtil.identityStrategy());
|
||||
private final Map<RefEntity, UnusedDeclarationHint> myFixedElements =
|
||||
ConcurrentCollectionFactory.createMap(ContainerUtil.identityStrategy());
|
||||
|
||||
@@ -155,7 +155,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
@NotNull Predicate<CommonProblemDescriptor> excludedDescriptions) {
|
||||
if (!(refEntity instanceof RefJavaElement)) return;
|
||||
final RefFilter filter = getFilter();
|
||||
if (!getIgnoredRefElements().contains(refEntity) && filter.accepts((RefJavaElement)refEntity)) {
|
||||
if (!myResolvedElements.contains(refEntity) && filter.accepts((RefJavaElement)refEntity)) {
|
||||
refEntity = getRefManager().getRefinedElement(refEntity);
|
||||
if (!refEntity.isValid()) return;
|
||||
RefJavaElement refElement = (RefJavaElement)refEntity;
|
||||
@@ -199,7 +199,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable InspectionTree tree) {
|
||||
boolean showFixes = false;
|
||||
for (RefEntity element : refElements) {
|
||||
if (!getIgnoredRefElements().contains(element) && element.isValid()) {
|
||||
if (!myResolvedElements.contains(element) && element.isValid()) {
|
||||
showFixes = true;
|
||||
break;
|
||||
}
|
||||
@@ -458,6 +458,15 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
};
|
||||
}
|
||||
|
||||
public void resolveElement(@NotNull RefEntity entity) {
|
||||
myProblemElements.remove(entity);
|
||||
myResolvedElements.add(entity);
|
||||
}
|
||||
|
||||
public boolean isProblemResolved(@Nullable RefEntity entity) {
|
||||
return myResolvedElements.contains(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContent() {
|
||||
getTool().checkForReachableRefs(getContext());
|
||||
@@ -468,7 +477,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
if (!(refEntity instanceof RefJavaElement)) return;//dead code doesn't work with refModule | refPackage
|
||||
RefJavaElement refElement = (RefJavaElement)refEntity;
|
||||
if (!compareVisibilities(refElement, localInspectionTool)) return;
|
||||
if (!(getContext().getUIOptions().FILTER_RESOLVED_ITEMS && getIgnoredRefElements().contains(refElement)) && refElement.isValid() && getFilter().accepts(refElement)) {
|
||||
if (!(getContext().getUIOptions().FILTER_RESOLVED_ITEMS && myResolvedElements.contains(refElement)) && refElement.isValid() && getFilter().accepts(refElement)) {
|
||||
if (skipEntryPoints(refElement)) return;
|
||||
registerContentEntry(refEntity, RefJavaUtil.getInstance().getPackageName(refEntity));
|
||||
}
|
||||
@@ -538,11 +547,6 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
return !myContents.isEmpty() || super.hasReportedProblems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignoreCurrentElement(@NotNull RefEntity refEntity) {
|
||||
myIgnoreElements.add(refEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignoreElement(@NotNull RefEntity refEntity) {
|
||||
if (refEntity instanceof RefElement) {
|
||||
@@ -563,18 +567,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
@Override
|
||||
public void cleanup() {
|
||||
super.cleanup();
|
||||
myIgnoreElements.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isElementIgnored(@NotNull RefEntity element) {
|
||||
return myIgnoreElements.contains(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Set<RefEntity> getIgnoredRefElements() {
|
||||
return myIgnoreElements;
|
||||
myResolvedElements.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+17
-16
@@ -292,13 +292,17 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
}
|
||||
|
||||
public void ignoreElement(@NotNull InspectionProfileEntry tool, @NotNull PsiElement element) {
|
||||
public void resolveElement(@NotNull InspectionProfileEntry tool, @NotNull PsiElement element) {
|
||||
final RefElement refElement = getRefManager().getReference(element);
|
||||
if (refElement == null) return;
|
||||
final Tools tools = getTools().get(tool.getShortName());
|
||||
if (tools != null){
|
||||
for (ScopeToolState state : tools.getTools()) {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
ignoreElementRecursively(toolWrapper, refElement);
|
||||
InspectionToolPresentation presentation = getPresentationOrNull(toolWrapper);
|
||||
if (presentation != null) {
|
||||
resolveElementRecursively(presentation, refElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,14 +315,11 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
return myOutputPath;
|
||||
}
|
||||
|
||||
private void ignoreElementRecursively(@NotNull InspectionToolWrapper toolWrapper, final RefEntity refElement) {
|
||||
if (refElement != null) {
|
||||
InspectionToolPresentation presentation = getPresentation(toolWrapper);
|
||||
presentation.ignoreCurrentElement(refElement);
|
||||
final List<RefEntity> children = refElement.getChildren();
|
||||
for (RefEntity child : children) {
|
||||
ignoreElementRecursively(toolWrapper, child);
|
||||
}
|
||||
private static void resolveElementRecursively(@NotNull InspectionToolPresentation presentation, @NotNull RefEntity refElement) {
|
||||
presentation.suppressProblem(refElement);
|
||||
final List<RefEntity> children = refElement.getChildren();
|
||||
for (RefEntity child : children) {
|
||||
resolveElementRecursively(presentation, child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,12 +865,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
myViewClosed = true;
|
||||
myView = null;
|
||||
((InspectionManagerEx)InspectionManager.getInstance(getProject())).closeRunningContext(this);
|
||||
for (Tools tools : getTools().values()) {
|
||||
for (ScopeToolState state : tools.getTools()) {
|
||||
InspectionToolWrapper toolWrapper = state.getTool();
|
||||
getPresentation(toolWrapper).cleanup();
|
||||
}
|
||||
}
|
||||
myPresentationMap.clear();
|
||||
super.close(noSuspiciousCodeFound);
|
||||
}
|
||||
|
||||
@@ -890,6 +886,11 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
|
||||
private final ConcurrentMap<InspectionToolWrapper, InspectionToolPresentation> myPresentationMap = ContainerUtil.newConcurrentMap();
|
||||
|
||||
@Nullable
|
||||
public InspectionToolPresentation getPresentationOrNull(@NotNull InspectionToolWrapper toolWrapper) {
|
||||
return myPresentationMap.get(toolWrapper);
|
||||
}
|
||||
@NotNull
|
||||
public InspectionToolPresentation getPresentation(@NotNull InspectionToolWrapper toolWrapper) {
|
||||
InspectionToolPresentation presentation = myPresentationMap.get(toolWrapper);
|
||||
|
||||
+7
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -24,6 +24,7 @@ import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.reference.RefModule;
|
||||
import com.intellij.codeInspection.ui.*;
|
||||
import com.intellij.codeInspection.ui.util.SynchronizedBidiMultiMap;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -31,7 +32,6 @@ 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.util.Function;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public abstract class InspectionRVContentProvider {
|
||||
@@ -140,8 +141,8 @@ public abstract class InspectionRVContentProvider {
|
||||
InspectionToolWrapper wrapper = toolNode.getToolWrapper();
|
||||
InspectionToolPresentation presentation = context.getPresentation(wrapper);
|
||||
Map<String, Set<RefEntity>> content = presentation.getContent();
|
||||
Map<RefEntity, CommonProblemDescriptor[]> problems = presentation.getProblemElements();
|
||||
return appendToolNodeContent(context, toolNode, parentNode, showStructure, groupBySeverity, content, problems);
|
||||
SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> problems = presentation.getProblemElements();
|
||||
return appendToolNodeContent(context, toolNode, parentNode, showStructure, groupBySeverity, content, problems::get);
|
||||
}
|
||||
|
||||
public abstract InspectionNode appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@@ -150,7 +151,7 @@ public abstract class InspectionRVContentProvider {
|
||||
final boolean showStructure,
|
||||
boolean groupBySeverity,
|
||||
@NotNull Map<String, Set<RefEntity>> contents,
|
||||
@NotNull Map<RefEntity, CommonProblemDescriptor[]> problems);
|
||||
@NotNull Function<RefEntity, CommonProblemDescriptor[]> problems);
|
||||
|
||||
protected abstract void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull InspectionToolWrapper toolWrapper,
|
||||
@@ -175,7 +176,7 @@ public abstract class InspectionRVContentProvider {
|
||||
for (String packageName : packageContents.keySet()) {
|
||||
final Set<T> elements = packageContents.get(packageName);
|
||||
for (T userObject : elements) {
|
||||
final RefEntityContainer container = computeContainer.fun(userObject);
|
||||
final RefEntityContainer container = computeContainer.apply(userObject);
|
||||
supportStructure &= container.supportStructure();
|
||||
final String moduleName = showStructure ? container.getModule() : null;
|
||||
Map<String, InspectionPackageNode> packageNodes = module2PackageMap.get(moduleName);
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -22,6 +22,7 @@ import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.reference.RefModule;
|
||||
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;
|
||||
@@ -34,6 +35,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class InspectionRVContentProviderImpl extends InspectionRVContentProvider {
|
||||
public InspectionRVContentProviderImpl(final Project project) {
|
||||
@@ -49,7 +51,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
final SearchScope searchScope = context.getCurrentScope().toSearchScope();
|
||||
if (searchScope instanceof LocalSearchScope) {
|
||||
final Map<String, Set<RefEntity>> contents = presentation.getContent();
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> problemElements = presentation.getProblemElements();
|
||||
final SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> problemElements = presentation.getProblemElements();
|
||||
for (Set<RefEntity> entities : contents.values()) {
|
||||
for (Iterator<RefEntity> iterator = entities.iterator(); iterator.hasNext(); ) {
|
||||
RefEntity entity = iterator.next();
|
||||
@@ -87,7 +89,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
final boolean showStructure,
|
||||
boolean groupBySeverity,
|
||||
@NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull final Map<RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
@NotNull final Function<RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
final InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
|
||||
InspectionNode mergedToolNode = (InspectionNode)merge(toolNode, parentNode, !groupBySeverity);
|
||||
|
||||
@@ -105,7 +107,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
contents,
|
||||
false,
|
||||
toolWrapper,
|
||||
refElement -> new RefEntityContainer<>(refElement, problems.get(refElement)),
|
||||
refElement -> new RefEntityContainer<>(refElement, problems.apply(refElement)),
|
||||
showStructure,
|
||||
node -> merge(node, mergedToolNode, true));
|
||||
return mergedToolNode;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -87,7 +87,7 @@ public class LocalQuickFixWrapper extends QuickFixAction {
|
||||
final Runnable refreshViews = () -> {
|
||||
DaemonCodeAnalyzer.getInstance(project).restart();
|
||||
for (CommonProblemDescriptor descriptor : descriptors) {
|
||||
ignore(ignoredElements, descriptor, getWorkingQuickFix(descriptor.getFixes()), context);
|
||||
ignore(ignoredElements, descriptor, getWorkingQuickFix(descriptor.getFixes()) != null, context);
|
||||
}
|
||||
|
||||
final RefManager refManager = context.getRefManager();
|
||||
@@ -113,7 +113,7 @@ public class LocalQuickFixWrapper extends QuickFixAction {
|
||||
//CCE here means QuickFix was incorrectly inherited, is there a way to signal (plugin) it is wrong?
|
||||
fix.applyFix(project, descriptor);
|
||||
restart = true;
|
||||
ignore(ignoredElements, descriptor, fix, context);
|
||||
ignore(ignoredElements, descriptor, true, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,11 +137,11 @@ public class LocalQuickFixWrapper extends QuickFixAction {
|
||||
|
||||
private void ignore(@NotNull Collection<PsiElement> ignoredElements,
|
||||
@NotNull CommonProblemDescriptor descriptor,
|
||||
@Nullable QuickFix fix,
|
||||
boolean hasFix,
|
||||
@NotNull GlobalInspectionContextImpl context) {
|
||||
if (fix != null) {
|
||||
if (hasFix) {
|
||||
InspectionToolPresentation presentation = context.getPresentation(myToolWrapper);
|
||||
presentation.ignoreProblem(descriptor, fix);
|
||||
presentation.resolveProblem(descriptor);
|
||||
}
|
||||
if (descriptor instanceof ProblemDescriptor) {
|
||||
PsiElement element = ((ProblemDescriptor)descriptor).getPsiElement();
|
||||
|
||||
@@ -160,10 +160,10 @@ public class QuickFixAction extends AnAction implements CustomComponentAction {
|
||||
refManager.inspectionReadActionFinished();
|
||||
|
||||
try {
|
||||
final Set<PsiElement> ignoredElements = new HashSet<>();
|
||||
performFixesInBatch(project, descriptors, context, ignoredElements);
|
||||
final Set<PsiElement> resolvedElements = new HashSet<>();
|
||||
performFixesInBatch(project, descriptors, context, resolvedElements);
|
||||
|
||||
refreshViews(project, ignoredElements, myToolWrapper);
|
||||
refreshViews(project, resolvedElements, myToolWrapper);
|
||||
}
|
||||
finally { //to make offline view lazy
|
||||
if (initial) refManager.inspectionReadActionStarted();
|
||||
@@ -270,20 +270,20 @@ public class QuickFixAction extends AnAction implements CustomComponentAction {
|
||||
return selection.toArray(new RefEntity[selection.size()]);
|
||||
}
|
||||
|
||||
private static void refreshViews(@NotNull Project project, @NotNull Set<PsiElement> selectedElements, @NotNull InspectionToolWrapper toolWrapper) {
|
||||
private static void refreshViews(@NotNull Project project, @NotNull Set<PsiElement> resolvedElements, @NotNull InspectionToolWrapper toolWrapper) {
|
||||
InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(project);
|
||||
final Set<GlobalInspectionContextImpl> runningContexts = managerEx.getRunningContexts();
|
||||
for (GlobalInspectionContextImpl context : runningContexts) {
|
||||
for (PsiElement element : selectedElements) {
|
||||
context.ignoreElement(toolWrapper.getTool(), element);
|
||||
for (PsiElement element : resolvedElements) {
|
||||
context.resolveElement(toolWrapper.getTool(), element);
|
||||
}
|
||||
context.refreshViews();
|
||||
}
|
||||
}
|
||||
|
||||
protected static void refreshViews(@NotNull Project project, @NotNull RefEntity[] refElements, @NotNull InspectionToolWrapper toolWrapper) {
|
||||
protected static void refreshViews(@NotNull Project project, @NotNull RefEntity[] resolvedElements, @NotNull InspectionToolWrapper toolWrapper) {
|
||||
final Set<PsiElement> ignoredElements = new HashSet<>();
|
||||
for (RefEntity element : refElements) {
|
||||
for (RefEntity element : resolvedElements) {
|
||||
final PsiElement psiElement = element instanceof RefElement ? ((RefElement)element).getElement() : null;
|
||||
if (psiElement != null && psiElement.isValid()) {
|
||||
ignoredElements.add(psiElement);
|
||||
|
||||
+8
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class OfflineInspectionRVContentProvider extends InspectionRVContentProvider {
|
||||
private final Map<String, Map<String, Set<OfflineProblemDescriptor>>> myContent;
|
||||
@@ -95,7 +96,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
|
||||
GlobalInspectionContextImpl context = tree.getContext();
|
||||
InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
|
||||
return presentation.extractActiveFixes(selectedRefElements, actions, tree.getSelectedDescriptors());
|
||||
return presentation.extractActiveFixes(selectedRefElements, actions::get, tree.getSelectedDescriptors());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,11 +106,11 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
|
||||
@Override
|
||||
public InspectionNode appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
|
||||
@NotNull final InspectionNode toolNode,
|
||||
@NotNull final InspectionTreeNode parentNode,
|
||||
final boolean showStructure,
|
||||
@NotNull InspectionNode toolNode,
|
||||
@NotNull InspectionTreeNode parentNode,
|
||||
boolean showStructure,
|
||||
boolean groupBySeverity, @NotNull final Map<String, Set<RefEntity>> contents,
|
||||
@NotNull final Map<RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
@NotNull Function<RefEntity, CommonProblemDescriptor[]> problems) {
|
||||
InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
|
||||
final Map<String, Set<OfflineProblemDescriptor>> filteredContent = getFilteredContent(context, toolWrapper);
|
||||
if (filteredContent != null && !filteredContent.values().isEmpty()) {
|
||||
@@ -143,7 +144,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
final Map<String, Set<OfflineProblemDescriptor>> current = new HashMap<>(content);
|
||||
content = null; //GC it
|
||||
InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
|
||||
for (RefEntity refEntity : presentation.getIgnoredRefElements()) {
|
||||
for (RefEntity refEntity : presentation.getResolvedElements()) {
|
||||
if (refEntity instanceof RefElement) {
|
||||
excludeProblem(refEntity.getExternalName(), current);
|
||||
}
|
||||
|
||||
+89
-194
@@ -23,7 +23,7 @@ import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.codeInspection.reference.*;
|
||||
import com.intellij.concurrency.ConcurrentCollectionFactory;
|
||||
import com.intellij.codeInspection.ui.util.SynchronizedBidiMultiMap;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
@@ -39,6 +39,7 @@ import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.ArrayFactory;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -52,9 +53,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class DefaultInspectionToolPresentation implements ProblemDescriptionsProcessor, InspectionToolPresentation {
|
||||
public class DefaultInspectionToolPresentation implements InspectionToolPresentation {
|
||||
protected static final Logger LOG = Logger.getInstance(DefaultInspectionToolPresentation.class);
|
||||
|
||||
@NotNull private final InspectionToolWrapper myToolWrapper;
|
||||
@@ -62,15 +64,15 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
protected InspectionNode myToolNode;
|
||||
|
||||
private final Object myLock = new Object();
|
||||
private final Map<RefEntity, CommonProblemDescriptor[]> myProblemElements =
|
||||
ConcurrentCollectionFactory.createMap(ContainerUtil.identityStrategy());
|
||||
|
||||
protected final SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> myProblemElements = createBidiMap();
|
||||
protected final SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> mySuppressedElements = createBidiMap();
|
||||
private final SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> myResolvedElements = createBidiMap();
|
||||
|
||||
protected final Map<String, Set<RefEntity>> myContents = Collections.synchronizedMap(new HashMap<String, Set<RefEntity>>(1)); // keys can be null
|
||||
private final Set<RefModule> myModulesProblems = Collections.synchronizedSet(ContainerUtil.newIdentityTroveSet());
|
||||
private final Map<CommonProblemDescriptor, RefEntity> myProblemToElements = Collections.synchronizedMap(ContainerUtil.newIdentityTroveMap());
|
||||
private DescriptorComposer myComposer;
|
||||
private final Map<RefEntity, Set<QuickFix>> myQuickFixActions = Collections.synchronizedMap(ContainerUtil.newIdentityTroveMap());
|
||||
private final Map<RefEntity, CommonProblemDescriptor[]> myIgnoredElements = Collections.synchronizedMap(ContainerUtil.newIdentityTroveMap());
|
||||
|
||||
private DescriptorComposer myComposer;
|
||||
private volatile boolean isDisposed;
|
||||
|
||||
public DefaultInspectionToolPresentation(@NotNull InspectionToolWrapper toolWrapper, @NotNull GlobalInspectionContextImpl context) {
|
||||
@@ -78,6 +80,53 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
public void resolveElement(@NotNull RefEntity entity) {
|
||||
CommonProblemDescriptor[] removed = myProblemElements.remove(entity);
|
||||
if (removed != null) {
|
||||
myResolvedElements.put(entity, removed);
|
||||
}
|
||||
}
|
||||
|
||||
public void resolveProblem(@NotNull CommonProblemDescriptor descriptor) {
|
||||
myResolvedElements.put(myProblemElements.removeValue(descriptor), descriptor);
|
||||
}
|
||||
|
||||
public boolean isProblemResolved(@Nullable CommonProblemDescriptor descriptor) {
|
||||
return myResolvedElements.containsValue(descriptor);
|
||||
}
|
||||
|
||||
public boolean isProblemResolved(@Nullable RefEntity entity) {
|
||||
return myResolvedElements.containsKey(entity);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<RefEntity> getResolvedElements() {
|
||||
return myResolvedElements.keys();
|
||||
}
|
||||
|
||||
public void suppressProblem(@NotNull CommonProblemDescriptor descriptor) {
|
||||
mySuppressedElements.put(myProblemElements.removeValue(descriptor), descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppressProblem(@NotNull RefEntity entity) {
|
||||
CommonProblemDescriptor[] removed = myProblemElements.remove(entity);
|
||||
if (removed != null) {
|
||||
mySuppressedElements.put(entity, removed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressed(RefEntity element) {
|
||||
return mySuppressedElements.containsKey(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressed(CommonProblemDescriptor descriptor) {
|
||||
return mySuppressedElements.containsValue(descriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public HighlightSeverity getSeverity(@NotNull RefElement element) {
|
||||
@@ -164,25 +213,14 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
if (descriptors.length == 0) return;
|
||||
if (filterSuppressed) {
|
||||
if (myContext.getOutputPath() == null || !(myToolWrapper instanceof LocalInspectionToolWrapper)) {
|
||||
synchronized (myLock) {
|
||||
Map<RefEntity, CommonProblemDescriptor[]> problemElements = getProblemElements();
|
||||
CommonProblemDescriptor[] problems = problemElements.get(refElement);
|
||||
problems = problems == null ? descriptors : mergeDescriptors(problems, descriptors);
|
||||
problemElements.put(refElement, problems);
|
||||
}
|
||||
for (CommonProblemDescriptor description : descriptors) {
|
||||
getProblemToElements().put(description, refElement);
|
||||
collectQuickFixes(description.getFixes(), refElement);
|
||||
}
|
||||
myProblemElements.put(refElement, descriptors);
|
||||
}
|
||||
else {
|
||||
writeOutput(descriptors, refElement);
|
||||
}
|
||||
}
|
||||
else { //just need to collect problems
|
||||
for (CommonProblemDescriptor descriptor : descriptors) {
|
||||
getProblemToElements().put(descriptor, refElement);
|
||||
}
|
||||
else {
|
||||
myProblemElements.put(refElement, descriptors);
|
||||
}
|
||||
|
||||
final GlobalInspectionContextImpl context = getContext();
|
||||
@@ -194,9 +232,10 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CommonProblemDescriptor[] mergeDescriptors(@NotNull CommonProblemDescriptor[] problems1,
|
||||
@NotNull CommonProblemDescriptor[] problems2) {
|
||||
public static CommonProblemDescriptor[] mergeDescriptors(CommonProblemDescriptor[] problems1,
|
||||
CommonProblemDescriptor[] problems2) {
|
||||
if (problems1 == null) return problems2;
|
||||
if (problems2 == null) return problems1;
|
||||
CommonProblemDescriptor[] out = new CommonProblemDescriptor[problems1.length + problems2.length];
|
||||
int o = problems1.length;
|
||||
Equality<CommonProblemDescriptor> equality = (o1, o2) -> {
|
||||
@@ -272,131 +311,23 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
@Override
|
||||
@NotNull
|
||||
public Collection<CommonProblemDescriptor> getProblemDescriptors() {
|
||||
return getProblemToElements().keySet();
|
||||
}
|
||||
|
||||
private void collectQuickFixes(final QuickFix[] fixes, @NotNull RefEntity refEntity) {
|
||||
if (fixes != null && fixes.length != 0) {
|
||||
Set<QuickFix> localQuickFixes = getQuickFixActions().computeIfAbsent(refEntity, k -> new HashSet<>());
|
||||
ContainerUtil.addAll(localQuickFixes, fixes);
|
||||
}
|
||||
return myProblemElements.getValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignoreElement(@NotNull final RefEntity refEntity) {
|
||||
final CommonProblemDescriptor[] removedDescriptors = getProblemElements().remove(refEntity);
|
||||
if (removedDescriptors != null) {
|
||||
for (CommonProblemDescriptor descriptor : removedDescriptors) {
|
||||
getProblemToElements().remove(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
getQuickFixActions().remove(refEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignoreCurrentElement(@NotNull RefEntity refEntity) {
|
||||
getIgnoredElements().put(refEntity, mergeDescriptors(getIgnoredElements().getOrDefault(refEntity, CommonProblemDescriptor.EMPTY_ARRAY),
|
||||
getProblemElements().getOrDefault(refEntity, CommonProblemDescriptor.EMPTY_ARRAY)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void amnesty(@NotNull RefEntity refEntity, @NotNull CommonProblemDescriptor descriptor) {
|
||||
final CommonProblemDescriptor[] ignoredDescriptors = getIgnoredElements().get(refEntity);
|
||||
if (ignoredDescriptors != null) {
|
||||
final CommonProblemDescriptor[] remainElements = ArrayUtil.remove(ignoredDescriptors, descriptor);
|
||||
if (remainElements.length != 0) {
|
||||
getIgnoredElements().put(refEntity, remainElements);
|
||||
} else {
|
||||
getIgnoredElements().remove(refEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ignoreProblem(@Nullable RefEntity refEntity, CommonProblemDescriptor problem, int idx) {
|
||||
if (refEntity == null) return;
|
||||
final Set<QuickFix> localQuickFixes = getQuickFixActions().get(refEntity);
|
||||
final QuickFix[] fixes = problem.getFixes();
|
||||
if (isIgnoreProblem(fixes, localQuickFixes, idx)){
|
||||
getProblemToElements().remove(problem);
|
||||
Map<RefEntity, CommonProblemDescriptor[]> problemElements = getProblemElements();
|
||||
synchronized (myLock) {
|
||||
CommonProblemDescriptor[] descriptors = problemElements.get(refEntity);
|
||||
if (descriptors != null) {
|
||||
ArrayList<CommonProblemDescriptor> newDescriptors = new ArrayList<>(Arrays.asList(descriptors));
|
||||
newDescriptors.remove(problem);
|
||||
CommonProblemDescriptor[] newDescriptorsAsArray = newDescriptors.toArray(new CommonProblemDescriptor[newDescriptors.size()]);
|
||||
getQuickFixActions().put(refEntity, null);
|
||||
if (!newDescriptors.isEmpty()) {
|
||||
problemElements.put(refEntity, newDescriptorsAsArray);
|
||||
for (CommonProblemDescriptor descriptor : newDescriptors) {
|
||||
collectQuickFixes(descriptor.getFixes(), refEntity);
|
||||
}
|
||||
}
|
||||
ignoreProblemElement(refEntity, newDescriptorsAsArray, problem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ignoreProblemElement(RefEntity refEntity, CommonProblemDescriptor[] newDescriptors, CommonProblemDescriptor toIgnore){
|
||||
if (newDescriptors != null && newDescriptors.length == 0) {
|
||||
newDescriptors = null;
|
||||
}
|
||||
if (newDescriptors == null) {
|
||||
getProblemElements().remove(refEntity);
|
||||
} else {
|
||||
getProblemElements().put(refEntity, newDescriptors);
|
||||
}
|
||||
CommonProblemDescriptor[] oldIgnored = getIgnoredElements().getOrDefault(refEntity, CommonProblemDescriptor.EMPTY_ARRAY);
|
||||
CommonProblemDescriptor[] update = new CommonProblemDescriptor[oldIgnored.length + 1];
|
||||
System.arraycopy(oldIgnored, 0, update, 0, oldIgnored.length);
|
||||
update[update.length - 1] = toIgnore;
|
||||
getIgnoredElements().put(refEntity, update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignoreCurrentElementProblem(@Nullable RefEntity refEntity, @Nullable CommonProblemDescriptor descriptor) {
|
||||
CommonProblemDescriptor[] descriptors = getIgnoredElements().get(refEntity);
|
||||
if (descriptors == null) {
|
||||
descriptors = CommonProblemDescriptor.EMPTY_ARRAY;
|
||||
}
|
||||
getIgnoredElements().put(refEntity, ArrayUtil.append(descriptors, descriptor));
|
||||
}
|
||||
|
||||
private static boolean isIgnoreProblem(QuickFix[] problemFixes, Set<QuickFix> fixes, int idx){
|
||||
if (problemFixes == null || fixes == null) {
|
||||
return true;
|
||||
}
|
||||
if (problemFixes.length <= idx){
|
||||
return true;
|
||||
}
|
||||
for (QuickFix fix : problemFixes) {
|
||||
if (fix != problemFixes[idx] && !fixes.contains(fix)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
myProblemElements.remove(refEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
synchronized (myLock) {
|
||||
myProblemElements.clear();
|
||||
myProblemToElements.clear();
|
||||
myQuickFixActions.clear();
|
||||
myIgnoredElements.clear();
|
||||
myContents.clear();
|
||||
myModulesProblems.clear();
|
||||
}
|
||||
|
||||
isDisposed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CommonProblemDescriptor[] getDescriptions(@NotNull RefEntity refEntity) {
|
||||
final CommonProblemDescriptor[] problems = getProblemElements().get(refEntity);
|
||||
final CommonProblemDescriptor[] problems = getProblemElements().getOrDefault(refEntity, null);
|
||||
if (problems == null) return null;
|
||||
|
||||
if (!refEntity.isValid()) {
|
||||
@@ -498,7 +429,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
|
||||
@Override
|
||||
public boolean hasReportedProblems() {
|
||||
return !myProblemToElements.isEmpty();
|
||||
return !myProblemElements.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -509,9 +440,9 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
|
||||
protected void updateProblemElements() {
|
||||
final Set<RefEntity> elements = getProblemElements().keySet();
|
||||
final Collection<RefEntity> elements = getProblemElements().keys();
|
||||
for (RefEntity element : elements) {
|
||||
if (getContext().getUIOptions().FILTER_RESOLVED_ITEMS && getIgnoredElements().containsKey(element)) continue;
|
||||
if (getContext().getUIOptions().FILTER_RESOLVED_ITEMS && (isProblemResolved(element) || isSuppressed(element))) continue;
|
||||
if (element instanceof RefModule) {
|
||||
myModulesProblems.add((RefModule)element);
|
||||
}
|
||||
@@ -542,18 +473,18 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
@Override
|
||||
@NotNull
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) {
|
||||
return extractActiveFixes(refElements, getProblemElements(), tree != null ? tree.getSelectedDescriptors() : null);
|
||||
return extractActiveFixes(refElements, getProblemElements()::get, tree != null ? tree.getSelectedDescriptors() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements,
|
||||
@NotNull Map<RefEntity, CommonProblemDescriptor[]> descriptorMap,
|
||||
@NotNull Function<RefEntity, CommonProblemDescriptor[]> descriptorMap,
|
||||
@Nullable CommonProblemDescriptor[] allowedDescriptors) {
|
||||
final Set<CommonProblemDescriptor> allowedDescriptorSet = allowedDescriptors == null ? null : ContainerUtil.newHashSet(allowedDescriptors);
|
||||
Map<String, LocalQuickFixWrapper> result = null;
|
||||
for (RefEntity refElement : refElements) {
|
||||
final CommonProblemDescriptor[] descriptors = descriptorMap.get(refElement);
|
||||
final CommonProblemDescriptor[] descriptors = descriptorMap.apply(refElement);
|
||||
if (descriptors == null) continue;
|
||||
for (CommonProblemDescriptor d : descriptors) {
|
||||
if (allowedDescriptorSet != null && !allowedDescriptorSet.contains(d)) {
|
||||
@@ -608,64 +539,15 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
|
||||
@Override
|
||||
public RefEntity getElement(@NotNull CommonProblemDescriptor descriptor) {
|
||||
return getProblemToElements().get(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignoreProblem(@NotNull CommonProblemDescriptor descriptor, @NotNull QuickFix fix) {
|
||||
RefEntity refElement = getProblemToElements().get(descriptor);
|
||||
if (refElement != null) {
|
||||
final QuickFix[] fixes = descriptor.getFixes();
|
||||
for (int i = 0; i < fixes.length; i++) {
|
||||
if (fixes[i] == fix){
|
||||
ignoreProblem(refElement, descriptor, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isElementIgnored(@NotNull RefEntity element) {
|
||||
return getIgnoredElements().containsKey(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProblemResolved(@Nullable RefEntity refEntity, @Nullable CommonProblemDescriptor descriptor) {
|
||||
if (descriptor == null) return true;
|
||||
CommonProblemDescriptor[] descriptors = getIgnoredElements().get(refEntity);
|
||||
return descriptors != null && ArrayUtil.contains(descriptor, descriptors);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<RefEntity> getIgnoredRefElements() {
|
||||
return getIgnoredElements().keySet();
|
||||
return myProblemElements.getKeyFor(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Map<RefEntity, CommonProblemDescriptor[]> getProblemElements() {
|
||||
public SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> getProblemElements() {
|
||||
return myProblemElements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<CommonProblemDescriptor, RefEntity> getProblemToElements() {
|
||||
return myProblemToElements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<RefEntity, Set<QuickFix>> getQuickFixActions() {
|
||||
return myQuickFixActions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<RefEntity, CommonProblemDescriptor[]> getIgnoredElements() {
|
||||
return myIgnoredElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createToolNode(@NotNull GlobalInspectionContextImpl globalInspectionContext, @NotNull InspectionNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
@@ -675,7 +557,6 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
myToolNode = node;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IntentionAction findQuickFixes(@NotNull final CommonProblemDescriptor problemDescriptor, final String hint) {
|
||||
@@ -722,4 +603,18 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> createBidiMap() {
|
||||
return new SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor>() {
|
||||
@Override
|
||||
public CommonProblemDescriptor[] merge(CommonProblemDescriptor[] values1, CommonProblemDescriptor[] values2) {
|
||||
return mergeDescriptors(values1, values2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayFactory<CommonProblemDescriptor> arrayFactory() {
|
||||
return CommonProblemDescriptor[]::new;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,12 +67,10 @@ import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.OpenSourceUtil;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -124,7 +122,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
private InspectionTreeLoadingProgressAware myLoadingProgressPreview;
|
||||
private final ExcludedInspectionTreeNodesManager myExcludedInspectionTreeNodesManager;
|
||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
||||
private final Map<String, Set<Object>> mySuppressedNodes = FactoryMap.createMap(key -> new THashSet<>());
|
||||
private final InspectionViewSuppressActionHolder mySuppressActionHolder = new InspectionViewSuppressActionHolder();
|
||||
|
||||
private final Object myTreeStructureUpdateLock = new Object();
|
||||
@@ -664,10 +661,6 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
return mySuppressActionHolder;
|
||||
}
|
||||
|
||||
public Set<Object> getSuppressedNodes(String toolId) {
|
||||
return mySuppressedNodes.get(toolId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ExcludedInspectionTreeNodesManager getExcludedManager() {
|
||||
return myExcludedInspectionTreeNodesManager;
|
||||
@@ -697,7 +690,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
}
|
||||
final InspectionNode toolNode = presentation.getToolNode();
|
||||
LOG.assertTrue(toolNode != null);
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<>();
|
||||
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);
|
||||
@@ -710,7 +703,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro
|
||||
uiOptions.SHOW_STRUCTURE,
|
||||
true,
|
||||
contents,
|
||||
problems);
|
||||
problems::get);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
+24
-14
@@ -18,11 +18,11 @@ package com.intellij.codeInspection.ui;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemDescriptionsProcessor;
|
||||
import com.intellij.codeInspection.QuickFix;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.reference.RefModule;
|
||||
import com.intellij.codeInspection.ui.util.SynchronizedBidiMultiMap;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -32,6 +32,7 @@ import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface InspectionToolPresentation extends ProblemDescriptionsProcessor {
|
||||
@@ -39,9 +40,6 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
@NotNull
|
||||
InspectionToolWrapper getToolWrapper();
|
||||
|
||||
@NotNull
|
||||
Map<RefEntity, CommonProblemDescriptor[]> getIgnoredElements();
|
||||
|
||||
void createToolNode(@NotNull GlobalInspectionContextImpl globalInspectionContext,
|
||||
@NotNull InspectionNode node,
|
||||
@NotNull InspectionRVContentProvider provider,
|
||||
@@ -64,12 +62,26 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
@NotNull
|
||||
Map<String, Set<RefEntity>> getContent();
|
||||
|
||||
void ignoreCurrentElement(@NotNull RefEntity refEntity);
|
||||
void amnesty(@NotNull RefEntity refEntity, @NotNull CommonProblemDescriptor descriptor);
|
||||
void cleanup();
|
||||
boolean isElementIgnored(@NotNull RefEntity element);
|
||||
void resolveElement(@NotNull RefEntity entity);
|
||||
|
||||
void resolveProblem(@NotNull CommonProblemDescriptor descriptor);
|
||||
|
||||
boolean isProblemResolved(@Nullable CommonProblemDescriptor descriptor);
|
||||
|
||||
boolean isProblemResolved(@Nullable RefEntity entity);
|
||||
|
||||
@NotNull
|
||||
Set<RefEntity> getIgnoredRefElements();
|
||||
Collection<RefEntity> getResolvedElements();
|
||||
|
||||
void suppressProblem(@NotNull CommonProblemDescriptor descriptor);
|
||||
|
||||
void suppressProblem(@NotNull RefEntity entity);
|
||||
|
||||
boolean isSuppressed(RefEntity element);
|
||||
|
||||
boolean isSuppressed(CommonProblemDescriptor descriptor);
|
||||
|
||||
void cleanup();
|
||||
@Nullable
|
||||
IntentionAction findQuickFixes(@NotNull CommonProblemDescriptor descriptor, final String hint);
|
||||
@NotNull
|
||||
@@ -80,19 +92,16 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
@NotNull
|
||||
QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable InspectionTree tree);
|
||||
@NotNull
|
||||
Map<RefEntity, CommonProblemDescriptor[]> getProblemElements();
|
||||
SynchronizedBidiMultiMap<RefEntity, CommonProblemDescriptor> getProblemElements();
|
||||
@NotNull
|
||||
Collection<CommonProblemDescriptor> getProblemDescriptors();
|
||||
boolean isProblemResolved(@Nullable RefEntity refEntity, @Nullable CommonProblemDescriptor descriptor);
|
||||
void ignoreCurrentElementProblem(@Nullable RefEntity refEntity, @Nullable CommonProblemDescriptor descriptor);
|
||||
void addProblemElement(@Nullable RefEntity refElement, boolean filterSuppressed, @NotNull CommonProblemDescriptor... descriptions);
|
||||
void ignoreProblem(@NotNull CommonProblemDescriptor descriptor, @NotNull QuickFix fix);
|
||||
|
||||
@NotNull
|
||||
GlobalInspectionContextImpl getContext();
|
||||
@NotNull
|
||||
QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements,
|
||||
@NotNull Map<RefEntity, CommonProblemDescriptor[]> descriptorMap,
|
||||
@NotNull Function<RefEntity, CommonProblemDescriptor[]> descriptorMap,
|
||||
@Nullable CommonProblemDescriptor[] allowedDescriptors);
|
||||
void exportResults(@NotNull Element parentNode,
|
||||
@NotNull Predicate<RefEntity> isEntityExcluded,
|
||||
@@ -117,4 +126,5 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
|
||||
@Nullable
|
||||
HighlightSeverity getSeverity(@NotNull RefElement element);
|
||||
|
||||
}
|
||||
|
||||
@@ -69,6 +69,11 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
myLineNumber = myDescriptor instanceof ProblemDescriptor ? ((ProblemDescriptor)myDescriptor).getLineNumber() : (lineNumberCounter == null ? -1 : lineNumberCounter.getAsInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAlreadySuppressedFromView() {
|
||||
return myDescriptor != null && getPresentation().isSuppressed(myDescriptor);
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return myLineNumber;
|
||||
}
|
||||
@@ -93,14 +98,9 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
return myDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemCount(boolean allowSuppressed) {
|
||||
return getPresentation().isProblemResolved(getElement(), myDescriptor) && !(allowSuppressed && isAlreadySuppressedFromView() && isValid())? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitProblemSeverities(TObjectIntHashMap<HighlightDisplayLevel> counter) {
|
||||
if (!getPresentation().isProblemResolved(getElement(), myDescriptor)) {
|
||||
if (!isExcluded() && !isQuickFixAppliedFromView() && !isAlreadySuppressedFromView()) {
|
||||
counter.put(myLevel, counter.get(myLevel) + 1);
|
||||
}
|
||||
}
|
||||
@@ -116,22 +116,6 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void excludeElement(ExcludedInspectionTreeNodesManager manager) {
|
||||
InspectionToolPresentation presentation = getPresentation();
|
||||
presentation.ignoreCurrentElementProblem(getElement(), getDescriptor());
|
||||
super.excludeElement(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void amnestyElement(ExcludedInspectionTreeNodesManager manager) {
|
||||
if (!isAlreadySuppressedFromView()) {
|
||||
InspectionToolPresentation presentation = getPresentation();
|
||||
presentation.amnesty(getElement(), getDescriptor());
|
||||
}
|
||||
super.amnestyElement(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropCache(Project project) {
|
||||
if (!isQuickFixAppliedFromView()) {
|
||||
@@ -151,7 +135,7 @@ public class ProblemDescriptionNode extends SuppressableInspectionTreeNode {
|
||||
|
||||
@Override
|
||||
public boolean isQuickFixAppliedFromView() {
|
||||
return (myDescriptor != null && getPresentation().isProblemResolved(getElement(), myDescriptor)) && !isAlreadySuppressedFromView();
|
||||
return (myDescriptor != null && getPresentation().isProblemResolved(myDescriptor)) && !isAlreadySuppressedFromView();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.reference.RefDirectory;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -45,6 +44,11 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
myIcon = refEntity == null ? null : refEntity.getIcon(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAlreadySuppressedFromView() {
|
||||
return getElement() != null && getPresentation().isSuppressed(getElement());
|
||||
}
|
||||
|
||||
public boolean hasDescriptorsUnder() {
|
||||
return myHasDescriptorsUnder;
|
||||
}
|
||||
@@ -75,16 +79,6 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
return refEntity != null && refEntity.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void excludeElement(ExcludedInspectionTreeNodesManager excludedManager) {
|
||||
super.excludeElement(excludedManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void amnestyElement(ExcludedInspectionTreeNodesManager excludedManager) {
|
||||
super.amnestyElement(excludedManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(MutableTreeNode newChild) {
|
||||
checkHasDescriptorUnder(newChild);
|
||||
@@ -115,14 +109,9 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
: super.getContainingFileLocalEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemCount(boolean allowSuppressed) {
|
||||
return isLeaf() ? getPresentation().getIgnoredRefElements().contains(getElement()) && !(allowSuppressed && isAlreadySuppressedFromView() && isValid()) ? 0 : 1 : super.getProblemCount(allowSuppressed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitProblemSeverities(TObjectIntHashMap<HighlightDisplayLevel> counter) {
|
||||
if (isLeaf() && !getPresentation().isElementIgnored(getElement())) {
|
||||
if (!isExcluded() && isLeaf() && !getPresentation().isProblemResolved(getElement()) && !getPresentation().isSuppressed(getElement())) {
|
||||
counter.put(HighlightDisplayLevel.WARNING, counter.get(HighlightDisplayLevel.WARNING) + 1);
|
||||
return;
|
||||
}
|
||||
@@ -131,7 +120,7 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
|
||||
|
||||
@Override
|
||||
public boolean isQuickFixAppliedFromView() {
|
||||
return false;
|
||||
return isLeaf() && getPresentation().isProblemResolved(getElement());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+17
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -55,19 +55,15 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
return isLeaf();
|
||||
}
|
||||
|
||||
public final boolean isAlreadySuppressedFromView() {
|
||||
final Object usrObj = getUserObject();
|
||||
if (usrObj != null) {
|
||||
InspectionResultsView view = myPresentation.getContext().getView();
|
||||
if (view != null && view.getSuppressedNodes(myPresentation.getToolWrapper().getShortName()).contains(usrObj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public abstract boolean isAlreadySuppressedFromView();
|
||||
|
||||
public abstract boolean isQuickFixAppliedFromView();
|
||||
|
||||
@Override
|
||||
public int getProblemCount(boolean allowSuppressed) {
|
||||
return !isExcluded() && isValid() && !isQuickFixAppliedFromView() && (allowSuppressed || !isAlreadySuppressedFromView()) ? 1 : 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<SuppressIntentionAction> getAvailableSuppressActions() {
|
||||
return myAvailableSuppressActions;
|
||||
@@ -115,10 +111,13 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
@Nullable
|
||||
@Override
|
||||
public String getTailText() {
|
||||
if (!isValid()) {
|
||||
return "No longer valid";
|
||||
if (isQuickFixAppliedFromView()) {
|
||||
return null;
|
||||
}
|
||||
return isAlreadySuppressedFromView() ? "Suppressed" : null;
|
||||
if (isAlreadySuppressedFromView()) {
|
||||
return "Suppressed";
|
||||
}
|
||||
return !isValid() ? "No longer valid" : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -163,4 +162,8 @@ public abstract class SuppressableInspectionTreeNode extends InspectionTreeNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isExcluded() {
|
||||
return getPresentation().getContext().getView().getExcludedManager().isExcluded(this);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-37
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -19,9 +19,7 @@ import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionManagerEx;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.ProblemDescriptionNode;
|
||||
import com.intellij.codeInspection.ui.SuppressableInspectionTreeNode;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -33,12 +31,9 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SequentialTask;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -50,17 +45,14 @@ public class SuppressActionSequentialTask implements SequentialTask {
|
||||
private SuppressableInspectionTreeNode[] myNodesToSuppress;
|
||||
@NotNull private final SuppressIntentionAction mySuppressAction;
|
||||
@NotNull private final InspectionToolWrapper myWrapper;
|
||||
@NotNull private final GlobalInspectionContextImpl myContext;
|
||||
private int myCount = 0;
|
||||
|
||||
public SuppressActionSequentialTask(@NotNull SuppressableInspectionTreeNode[] nodesToSuppress,
|
||||
@NotNull SuppressIntentionAction suppressAction,
|
||||
@NotNull InspectionToolWrapper wrapper,
|
||||
@NotNull GlobalInspectionContextImpl context) {
|
||||
@NotNull InspectionToolWrapper wrapper) {
|
||||
myNodesToSuppress = nodesToSuppress;
|
||||
mySuppressAction = suppressAction;
|
||||
myWrapper = wrapper;
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,36 +124,11 @@ public class SuppressActionSequentialTask implements SequentialTask {
|
||||
final Set<GlobalInspectionContextImpl> globalInspectionContexts =
|
||||
((InspectionManagerEx)InspectionManager.getInstance(element.getProject())).getRunningContexts();
|
||||
for (GlobalInspectionContextImpl context : globalInspectionContexts) {
|
||||
context.ignoreElement(wrapper.getTool(), container);
|
||||
context.resolveElement(wrapper.getTool(), container);
|
||||
if (descriptor != null) {
|
||||
context.getPresentation(wrapper).ignoreCurrentElementProblem(refEntity, descriptor);
|
||||
context.getPresentation(wrapper).suppressProblem(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
final RefElement containerRef = refEntity.getRefManager().getReference(container);
|
||||
final Set<Object> suppressedNodes = myContext.getView().getSuppressedNodes(wrapper.getShortName());
|
||||
if (containerRef != null) {
|
||||
Queue<RefEntity> toIgnoreInView = new Queue<>(1);
|
||||
toIgnoreInView.addLast(containerRef);
|
||||
while (!toIgnoreInView.isEmpty()) {
|
||||
final RefEntity entity = toIgnoreInView.pullFirst();
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
final CommonProblemDescriptor[] descriptors = myContext.getPresentation(wrapper).getIgnoredElements().get(entity);
|
||||
if (descriptors != null) {
|
||||
Collections.addAll(suppressedNodes, descriptors);
|
||||
}
|
||||
} else {
|
||||
suppressedNodes.add(entity);
|
||||
}
|
||||
final List<RefEntity> children = entity.getChildren();
|
||||
for (RefEntity child : children) {
|
||||
toIgnoreInView.addLast(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
suppressedNodes.add(descriptor);
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e1) {
|
||||
LOG.error(e1);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -102,7 +102,7 @@ public class SuppressActionWrapper extends ActionGroup implements CompactActionG
|
||||
final SequentialModalProgressTask progressTask =
|
||||
new SequentialModalProgressTask(project, templatePresentationText, true);
|
||||
progressTask.setMinIterationTime(200);
|
||||
progressTask.setTask(new SuppressActionSequentialTask(nodes, mySuppressAction, wrapper, view.getGlobalInspectionContext()));
|
||||
progressTask.setTask(new SuppressActionSequentialTask(nodes, mySuppressAction, wrapper));
|
||||
ProgressManager.getInstance().run(progressTask);
|
||||
}, templatePresentationText, null);
|
||||
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.util;
|
||||
|
||||
import com.intellij.util.ArrayFactory;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import gnu.trove.THashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class SynchronizedBidiMultiMap<K, V> {
|
||||
private final Map<K, V[]> myKey2Values = new THashMap<>();
|
||||
private final Map<V, K> myValue2Keys = new THashMap<>();
|
||||
|
||||
public synchronized Collection<K> keys() {
|
||||
return new ArrayList<>(myKey2Values.keySet());
|
||||
}
|
||||
|
||||
public synchronized boolean containsKey(K key) {
|
||||
return myKey2Values.containsKey(key);
|
||||
}
|
||||
|
||||
public synchronized boolean containsValue(V value) {
|
||||
return myValue2Keys.containsKey(value);
|
||||
}
|
||||
|
||||
public synchronized K getKeyFor(V value) {
|
||||
return myValue2Keys.get(value);
|
||||
}
|
||||
|
||||
public synchronized V[] get(K key) {
|
||||
return myKey2Values.get(key);
|
||||
}
|
||||
public synchronized V[] getOrDefault(K key, V[] defaultValue) {
|
||||
V[] values = get(key);
|
||||
return values == null ? defaultValue : values;
|
||||
}
|
||||
|
||||
public synchronized void put(K key, V... values) {
|
||||
myKey2Values.merge(key, values, this::merge);
|
||||
for (V value : values) {
|
||||
myValue2Keys.put(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return new elements or null!
|
||||
*/
|
||||
public synchronized V[] remove(K key, V value) {
|
||||
V[] newValues = myKey2Values.computeIfPresent(key, (k, vs) -> {
|
||||
V[] removed = ArrayUtil.remove(vs, value, arrayFactory());
|
||||
if (removed.length == 0) return null;
|
||||
return removed;
|
||||
});
|
||||
myValue2Keys.remove(value);
|
||||
return newValues;
|
||||
}
|
||||
|
||||
public synchronized K removeValue(V value) {
|
||||
K key = myValue2Keys.get(value);
|
||||
if (key != null) {
|
||||
remove(key, value);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public synchronized V[] remove(K key) {
|
||||
V[] removed = myKey2Values.remove(key);
|
||||
if (removed != null) {
|
||||
for (V v : removed) {
|
||||
myValue2Keys.remove(v);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public synchronized Collection<V> getValues() {
|
||||
return myValue2Keys.keySet();
|
||||
}
|
||||
|
||||
public synchronized boolean isEmpty() {
|
||||
return myValue2Keys.isEmpty();
|
||||
}
|
||||
|
||||
public abstract V[] merge(V[] values1, V[] values2);
|
||||
|
||||
public abstract ArrayFactory<V> arrayFactory();
|
||||
}
|
||||
Reference in New Issue
Block a user