inspection view: get rid of global lock in presentation

This commit is contained in:
Dmitry Batkovich
2017-08-22 11:24:19 +03:00
parent c2919a4e96
commit 2944c84331
16 changed files with 321 additions and 379 deletions
@@ -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
@@ -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);
@@ -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);
@@ -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);
@@ -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);
}
@@ -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);
}
}
}));
@@ -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
@@ -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);
}
}
@@ -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);
@@ -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);
@@ -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();
}