| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.codeInspection.ui; |
| |
| import com.intellij.codeHighlighting.HighlightDisplayLevel; |
| import com.intellij.codeInsight.daemon.HighlightDisplayKey; |
| import com.intellij.codeInsight.daemon.impl.HighlightInfoType; |
| import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; |
| import com.intellij.codeInsight.intention.IntentionAction; |
| import com.intellij.codeInspection.*; |
| import com.intellij.codeInspection.ex.*; |
| import com.intellij.codeInspection.reference.*; |
| import com.intellij.lang.annotation.HighlightSeverity; |
| import com.intellij.openapi.components.PathMacroManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.JDOMUtil; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vcs.FileStatus; |
| import com.intellij.profile.codeInspection.InspectionProjectProfileManager; |
| import com.intellij.profile.codeInspection.InspectionProjectProfileManagerImpl; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.IncorrectOperationException; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.containers.HashSet; |
| import com.intellij.util.ui.UIUtil; |
| import gnu.trove.THashMap; |
| import org.jdom.Element; |
| import org.jdom.IllegalDataException; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.tree.DefaultTreeModel; |
| import java.io.*; |
| import java.util.*; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public class DefaultInspectionToolPresentation implements ProblemDescriptionsProcessor, InspectionToolPresentation { |
| @NotNull private final InspectionToolWrapper myToolWrapper; |
| |
| @NotNull |
| private final GlobalInspectionContextImpl myContext; |
| protected static String ourOutputPath; |
| protected InspectionNode myToolNode; |
| |
| private static final Object lock = new Object(); |
| private Map<RefEntity, CommonProblemDescriptor[]> myProblemElements; |
| private Map<String, Set<RefEntity>> myContents = null; |
| private Set<RefModule> myModulesProblems = null; |
| private Map<CommonProblemDescriptor, RefEntity> myProblemToElements; |
| private DescriptorComposer myComposer; |
| private Map<RefEntity, Set<QuickFix>> myQuickFixActions; |
| private Map<RefEntity, CommonProblemDescriptor[]> myIgnoredElements; |
| |
| private Map<RefEntity, CommonProblemDescriptor[]> myOldProblemElements = null; |
| protected static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.DescriptorProviderInspection"); |
| private boolean isDisposed; |
| |
| public DefaultInspectionToolPresentation(@NotNull InspectionToolWrapper toolWrapper, @NotNull GlobalInspectionContextImpl context) { |
| myToolWrapper = toolWrapper; |
| myContext = context; |
| } |
| |
| @NotNull |
| protected static FileStatus calcStatus(boolean old, boolean current) { |
| if (old) { |
| if (!current) { |
| return FileStatus.DELETED; |
| } |
| } |
| else if (current) { |
| return FileStatus.ADDED; |
| } |
| return FileStatus.NOT_CHANGED; |
| } |
| |
| public static String stripUIRefsFromInspectionDescription(String description) { |
| final int descriptionEnd = description.indexOf("<!-- tooltip end -->"); |
| if (descriptionEnd < 0) { |
| final Pattern pattern = Pattern.compile(".*Use.*(the (panel|checkbox|checkboxes|field|button|controls).*below).*", Pattern.DOTALL); |
| final Matcher matcher = pattern.matcher(description); |
| int startFindIdx = 0; |
| while (matcher.find(startFindIdx)) { |
| final int end = matcher.end(1); |
| startFindIdx = end; |
| description = description.substring(0, matcher.start(1)) + " inspection settings " + description.substring(end); |
| } |
| } else { |
| description = description.substring(0, descriptionEnd); |
| } |
| return description; |
| } |
| |
| protected HighlightSeverity getSeverity(@NotNull RefElement element) { |
| final PsiElement psiElement = element.getPointer().getContainingFile(); |
| if (psiElement != null) { |
| final GlobalInspectionContextImpl context = getContext(); |
| final String shortName = getSeverityDelegateName(); |
| final Tools tools = context.getTools().get(shortName); |
| if (tools != null) { |
| for (ScopeToolState state : tools.getTools()) { |
| InspectionToolWrapper toolWrapper = state.getTool(); |
| if (toolWrapper == getToolWrapper()) { |
| return context.getCurrentProfile().getErrorLevel(HighlightDisplayKey.find(shortName), psiElement).getSeverity(); |
| } |
| } |
| } |
| |
| final InspectionProfile profile = InspectionProjectProfileManager.getInstance(context.getProject()).getInspectionProfile(); |
| final HighlightDisplayLevel level = profile.getErrorLevel(HighlightDisplayKey.find(shortName), psiElement); |
| return level.getSeverity(); |
| } |
| return null; |
| } |
| |
| protected String getSeverityDelegateName() { |
| return getToolWrapper().getShortName(); |
| } |
| |
| protected static String getTextAttributeKey(@NotNull Project project, |
| @NotNull HighlightSeverity severity, |
| @NotNull ProblemHighlightType highlightType) { |
| if (highlightType == ProblemHighlightType.LIKE_DEPRECATED) { |
| return HighlightInfoType.DEPRECATED.getAttributesKey().getExternalName(); |
| } |
| if (highlightType == ProblemHighlightType.LIKE_UNKNOWN_SYMBOL && severity == HighlightSeverity.ERROR) { |
| return HighlightInfoType.WRONG_REF.getAttributesKey().getExternalName(); |
| } |
| if (highlightType == ProblemHighlightType.LIKE_UNUSED_SYMBOL) { |
| return HighlightInfoType.UNUSED_SYMBOL.getAttributesKey().getExternalName(); |
| } |
| SeverityRegistrar registrar = InspectionProjectProfileManagerImpl.getInstanceImpl(project).getSeverityRegistrar(); |
| return registrar.getHighlightInfoTypeBySeverity(severity).getAttributesKey().getExternalName(); |
| } |
| |
| @NotNull |
| public InspectionToolWrapper getToolWrapper() { |
| return myToolWrapper; |
| } |
| |
| @NotNull |
| public RefManager getRefManager() { |
| return getContext().getRefManager(); |
| } |
| |
| @NotNull |
| @Override |
| public GlobalInspectionContextImpl getContext() { |
| return myContext; |
| } |
| |
| @Override |
| public void exportResults(@NotNull final Element parentNode) { |
| getRefManager().iterate(new RefVisitor(){ |
| @Override |
| public void visitElement(@NotNull RefEntity elem) { |
| exportResults(parentNode, elem); |
| } |
| }); |
| } |
| |
| @Override |
| public boolean isOldProblemsIncluded() { |
| final GlobalInspectionContextImpl context = getContext(); |
| return context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN && getOldContent() != null; |
| } |
| |
| |
| @Override |
| public void addProblemElement(RefEntity refElement, @NotNull CommonProblemDescriptor... descriptions){ |
| addProblemElement(refElement, true, descriptions); |
| } |
| |
| @Override |
| public void addProblemElement(RefEntity refElement, boolean filterSuppressed, @NotNull CommonProblemDescriptor... descriptors) { |
| if (refElement == null) return; |
| if (descriptors.length == 0) return; |
| if (filterSuppressed) { |
| if (ourOutputPath == null || !(myToolWrapper instanceof LocalInspectionToolWrapper)) { |
| synchronized (lock) { |
| Map<RefEntity, CommonProblemDescriptor[]> problemElements = getProblemElements(); |
| CommonProblemDescriptor[] problems = problemElements.get(refElement); |
| problems = problems == null ? descriptors : ArrayUtil.mergeArrays(problems, descriptors, CommonProblemDescriptor.ARRAY_FACTORY); |
| problemElements.put(refElement, problems); |
| } |
| for (CommonProblemDescriptor description : descriptors) { |
| getProblemToElements().put(description, refElement); |
| collectQuickFixes(description.getFixes(), refElement); |
| } |
| } |
| else { |
| writeOutput(descriptors, refElement); |
| } |
| } |
| else { //just need to collect problems |
| for (CommonProblemDescriptor descriptor : descriptors) { |
| getProblemToElements().put(descriptor, refElement); |
| } |
| } |
| |
| final GlobalInspectionContextImpl context = getContext(); |
| if (myToolWrapper instanceof LocalInspectionToolWrapper) { |
| final InspectionResultsView view = context.getView(); |
| if (view == null || !(refElement instanceof RefElement)) { |
| return; |
| } |
| InspectionNode toolNode = myToolNode; |
| if (toolNode == null) { |
| final HighlightSeverity currentSeverity = getSeverity((RefElement)refElement); |
| view.addTool(myToolWrapper, HighlightDisplayLevel.find(currentSeverity), context.getUIOptions().GROUP_BY_SEVERITY); |
| } |
| else if (toolNode.isTooBigForOnlineRefresh()) { |
| return; |
| } |
| final Map<RefEntity, CommonProblemDescriptor[]> problems = new HashMap<RefEntity, CommonProblemDescriptor[]>(); |
| problems.put(refElement, descriptors); |
| final Map<String, Set<RefEntity>> contents = new HashMap<String, Set<RefEntity>>(); |
| final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement); |
| Set<RefEntity> content = contents.get(groupName); |
| if (content == null) { |
| content = new HashSet<RefEntity>(); |
| contents.put(groupName, content); |
| } |
| content.add(refElement); |
| |
| UIUtil.invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| if (!isDisposed()) { |
| view.getProvider().appendToolNodeContent(context, myToolNode, |
| (InspectionTreeNode)myToolNode.getParent(), context.getUIOptions().SHOW_STRUCTURE, |
| contents, problems, (DefaultTreeModel)view.getTree().getModel()); |
| context.addView(view); |
| } |
| } |
| }); |
| |
| } |
| } |
| |
| protected boolean isDisposed() { |
| return isDisposed; |
| } |
| |
| private void writeOutput(@NotNull final CommonProblemDescriptor[] descriptions, @NotNull RefEntity refElement) { |
| final Element parentNode = new Element(InspectionsBundle.message("inspection.problems")); |
| exportResults(descriptions, refElement, parentNode); |
| final List list = parentNode.getChildren(); |
| |
| @NonNls final String ext = ".xml"; |
| final String fileName = ourOutputPath + File.separator + myToolWrapper.getShortName() + ext; |
| final PathMacroManager pathMacroManager = PathMacroManager.getInstance(getContext().getProject()); |
| PrintWriter printWriter = null; |
| try { |
| new File(ourOutputPath).mkdirs(); |
| final File file = new File(fileName); |
| final CharArrayWriter writer = new CharArrayWriter(); |
| if (!file.exists()) { |
| writer.append("<").append(InspectionsBundle.message("inspection.problems")).append(" " + GlobalInspectionContextImpl.LOCAL_TOOL_ATTRIBUTE + "=\"") |
| .append(Boolean.toString(myToolWrapper instanceof LocalInspectionToolWrapper)).append("\">\n"); |
| } |
| for (Object o : list) { |
| final Element element = (Element)o; |
| pathMacroManager.collapsePaths(element); |
| JDOMUtil.writeElement(element, writer, "\n"); |
| } |
| printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName, true), "UTF-8"))); |
| printWriter.append("\n"); |
| printWriter.append(writer.toString()); |
| } |
| catch (IOException e) { |
| LOG.error(e); |
| } |
| finally { |
| if (printWriter != null) { |
| printWriter.close(); |
| } |
| } |
| } |
| |
| @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().get(refEntity); |
| if (localQuickFixes == null) { |
| localQuickFixes = new HashSet<QuickFix>(); |
| getQuickFixActions().put(refEntity, localQuickFixes); |
| } |
| ContainerUtil.addAll(localQuickFixes, fixes); |
| } |
| } |
| |
| @Override |
| public void ignoreElement(@NotNull final RefEntity refEntity) { |
| getProblemElements().remove(refEntity); |
| getQuickFixActions().remove(refEntity); |
| } |
| |
| @Override |
| public void ignoreCurrentElement(RefEntity refEntity) { |
| if (refEntity == null) return; |
| getIgnoredElements().put(refEntity, getProblemElements().get(refEntity)); |
| } |
| |
| @Override |
| public void amnesty(RefEntity refEntity) { |
| getIgnoredElements().remove(refEntity); |
| } |
| |
| @Override |
| public void ignoreProblem(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 (lock) { |
| CommonProblemDescriptor[] descriptors = problemElements.get(refEntity); |
| if (descriptors != null) { |
| ArrayList<CommonProblemDescriptor> newDescriptors = new ArrayList<CommonProblemDescriptor>(Arrays.asList(descriptors)); |
| newDescriptors.remove(problem); |
| getQuickFixActions().put(refEntity, null); |
| if (!newDescriptors.isEmpty()) { |
| problemElements.put(refEntity, newDescriptors.toArray(new CommonProblemDescriptor[newDescriptors.size()])); |
| for (CommonProblemDescriptor descriptor : newDescriptors) { |
| collectQuickFixes(descriptor.getFixes(), refEntity); |
| } |
| } |
| else { |
| ignoreProblemElement(refEntity); |
| } |
| } |
| } |
| } |
| } |
| |
| private void ignoreProblemElement(RefEntity refEntity){ |
| final CommonProblemDescriptor[] problemDescriptors = getProblemElements().remove(refEntity); |
| getIgnoredElements().put(refEntity, problemDescriptors); |
| } |
| |
| @Override |
| public void ignoreCurrentElementProblem(RefEntity refEntity, CommonProblemDescriptor descriptor) { |
| CommonProblemDescriptor[] descriptors = getIgnoredElements().get(refEntity); |
| if (descriptors == null) { |
| descriptors = new CommonProblemDescriptor[0]; |
| } |
| 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; |
| } |
| |
| @Override |
| public void cleanup() { |
| myOldProblemElements = null; |
| |
| synchronized (lock) { |
| myProblemElements = null; |
| myProblemToElements = null; |
| myQuickFixActions = null; |
| myIgnoredElements = null; |
| } |
| |
| myContents = null; |
| myModulesProblems = null; |
| isDisposed = true; |
| } |
| |
| @Override |
| public void finalCleanup() { |
| myOldProblemElements = null; |
| cleanup(); |
| } |
| |
| @Override |
| @Nullable |
| public CommonProblemDescriptor[] getDescriptions(@NotNull RefEntity refEntity) { |
| final CommonProblemDescriptor[] problems = getProblemElements().get(refEntity); |
| if (problems == null) return null; |
| |
| if (!refEntity.isValid()) { |
| ignoreElement(refEntity); |
| return null; |
| } |
| |
| return problems; |
| } |
| |
| @NotNull |
| @Override |
| public HTMLComposerImpl getComposer() { |
| if (myComposer == null) { |
| myComposer = new DescriptorComposer(this); |
| } |
| return myComposer; |
| } |
| |
| @Override |
| public void exportResults(@NotNull final Element parentNode, @NotNull RefEntity refEntity) { |
| synchronized (lock) { |
| if (getProblemElements().containsKey(refEntity)) { |
| CommonProblemDescriptor[] descriptions = getDescriptions(refEntity); |
| if (descriptions != null) { |
| exportResults(descriptions, refEntity, parentNode); |
| } |
| } |
| } |
| } |
| |
| private void exportResults(@NotNull final CommonProblemDescriptor[] descriptors, @NotNull RefEntity refEntity, @NotNull Element parentNode) { |
| for (CommonProblemDescriptor descriptor : descriptors) { |
| @NonNls final String template = descriptor.getDescriptionTemplate(); |
| int line = descriptor instanceof ProblemDescriptor ? ((ProblemDescriptor)descriptor).getLineNumber() : -1; |
| final PsiElement psiElement = descriptor instanceof ProblemDescriptor ? ((ProblemDescriptor)descriptor).getPsiElement() : null; |
| @NonNls String problemText = StringUtil.replace(StringUtil.replace(template, "#ref", psiElement != null ? ProblemDescriptorUtil |
| .extractHighlightedText(descriptor, psiElement) : ""), " #loc ", " "); |
| |
| Element element = refEntity.getRefManager().export(refEntity, parentNode, line); |
| if (element == null) return; |
| @NonNls Element problemClassElement = new Element(InspectionsBundle.message("inspection.export.results.problem.element.tag")); |
| problemClassElement.addContent(myToolWrapper.getDisplayName()); |
| if (refEntity instanceof RefElement){ |
| final RefElement refElement = (RefElement)refEntity; |
| final HighlightSeverity severity = getSeverity(refElement); |
| ProblemHighlightType problemHighlightType = descriptor instanceof ProblemDescriptor |
| ? ((ProblemDescriptor)descriptor).getHighlightType() |
| : ProblemHighlightType.GENERIC_ERROR_OR_WARNING; |
| final String attributeKey = getTextAttributeKey(refElement.getRefManager().getProject(), severity, problemHighlightType); |
| problemClassElement.setAttribute("severity", severity.myName); |
| problemClassElement.setAttribute("attribute_key", attributeKey); |
| } |
| element.addContent(problemClassElement); |
| if (myToolWrapper instanceof GlobalInspectionToolWrapper) { |
| final GlobalInspectionTool globalInspectionTool = ((GlobalInspectionToolWrapper)myToolWrapper).getTool(); |
| final QuickFix[] fixes = descriptor.getFixes(); |
| if (fixes != null) { |
| @NonNls Element hintsElement = new Element("hints"); |
| for (QuickFix fix : fixes) { |
| final String hint = globalInspectionTool.getHint(fix); |
| if (hint != null) { |
| @NonNls Element hintElement = new Element("hint"); |
| hintElement.setAttribute("value", hint); |
| hintsElement.addContent(hintElement); |
| } |
| } |
| element.addContent(hintsElement); |
| } |
| } |
| try { |
| Element descriptionElement = new Element(InspectionsBundle.message("inspection.export.results.description.tag")); |
| descriptionElement.addContent(problemText); |
| element.addContent(descriptionElement); |
| } |
| catch (IllegalDataException e) { |
| //noinspection HardCodedStringLiteral,UseOfSystemOutOrSystemErr |
| System.out.println("Cannot save results for " + refEntity.getName() + ", inspection which caused problem: " + myToolWrapper.getShortName()); |
| } |
| } |
| } |
| |
| @Override |
| public boolean isGraphNeeded() { |
| return false; |
| } |
| |
| @Override |
| public boolean hasReportedProblems() { |
| final GlobalInspectionContextImpl context = getContext(); |
| if (!isDisposed() && context.getUIOptions().SHOW_ONLY_DIFF) { |
| for (CommonProblemDescriptor descriptor : getProblemToElements().keySet()) { |
| if (getProblemStatus(descriptor) != FileStatus.NOT_CHANGED) { |
| return true; |
| } |
| } |
| if (myOldProblemElements != null) { |
| for (RefEntity entity : myOldProblemElements.keySet()) { |
| if (getElementStatus(entity) != FileStatus.NOT_CHANGED) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| if (!getProblemElements().isEmpty()) return true; |
| return !isDisposed() && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN && myOldProblemElements != null && !myOldProblemElements.isEmpty(); |
| } |
| |
| @Override |
| public void updateContent() { |
| myContents = new com.intellij.util.containers.HashMap<String, Set<RefEntity>>(); |
| myModulesProblems = new HashSet<RefModule>(); |
| final Set<RefEntity> elements = getProblemElements().keySet(); |
| for (RefEntity element : elements) { |
| if (getContext().getUIOptions().FILTER_RESOLVED_ITEMS && getIgnoredElements().containsKey(element)) continue; |
| if (element instanceof RefModule) { |
| myModulesProblems.add((RefModule)element); |
| } |
| else { |
| String groupName = element instanceof RefElement ? element.getRefManager().getGroupName((RefElement)element) : null; |
| Set<RefEntity> content = myContents.get(groupName); |
| if (content == null) { |
| content = new HashSet<RefEntity>(); |
| myContents.put(groupName, content); |
| } |
| content.add(element); |
| } |
| } |
| } |
| |
| @Override |
| public Map<String, Set<RefEntity>> getContent() { |
| return myContents; |
| } |
| |
| @Override |
| public Map<String, Set<RefEntity>> getOldContent() { |
| if (myOldProblemElements == null) return null; |
| final com.intellij.util.containers.HashMap<String, Set<RefEntity>> |
| oldContents = new com.intellij.util.containers.HashMap<String, Set<RefEntity>>(); |
| final Set<RefEntity> elements = myOldProblemElements.keySet(); |
| for (RefEntity element : elements) { |
| String groupName = element instanceof RefElement ? element.getRefManager().getGroupName((RefElement)element) : element.getName(); |
| final Set<RefEntity> collection = myContents.get(groupName); |
| if (collection != null) { |
| final Set<RefEntity> currentElements = new HashSet<RefEntity>(collection); |
| if (RefUtil.contains(element, currentElements)) continue; |
| } |
| Set<RefEntity> oldContent = oldContents.get(groupName); |
| if (oldContent == null) { |
| oldContent = new HashSet<RefEntity>(); |
| oldContents.put(groupName, oldContent); |
| } |
| oldContent.add(element); |
| } |
| return oldContents; |
| } |
| |
| @Override |
| public Set<RefModule> getModuleProblems() { |
| return myModulesProblems; |
| } |
| |
| @Override |
| @Nullable |
| public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { |
| return extractActiveFixes(refElements, getQuickFixActions()); |
| } |
| |
| @Override |
| @Nullable |
| public QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, @NotNull Map<RefEntity, Set<QuickFix>> actions) { |
| Map<Class, QuickFixAction> result = new com.intellij.util.containers.HashMap<Class, QuickFixAction>(); |
| for (RefEntity refElement : refElements) { |
| final Set<QuickFix> localQuickFixes = actions.get(refElement); |
| if (localQuickFixes == null) continue; |
| for (QuickFix fix : localQuickFixes) { |
| if (fix == null) continue; |
| final Class klass = fix instanceof ActionClassHolder ? ((ActionClassHolder ) fix).getActionClass() : fix.getClass(); |
| final QuickFixAction quickFixAction = result.get(klass); |
| if (quickFixAction != null) { |
| try { |
| String familyName = fix.getFamilyName(); |
| familyName = !familyName.isEmpty() ? "\'" + familyName + "\'" : familyName; |
| ((LocalQuickFixWrapper)quickFixAction).setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", familyName)); |
| } |
| catch (AbstractMethodError e) { |
| //for plugin compatibility |
| ((LocalQuickFixWrapper)quickFixAction).setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", "")); |
| } |
| } |
| else { |
| LocalQuickFixWrapper quickFixWrapper = new LocalQuickFixWrapper(fix, myToolWrapper); |
| result.put(klass, quickFixWrapper); |
| } |
| } |
| } |
| return result.values().isEmpty() ? null : result.values().toArray(new QuickFixAction[result.size()]); |
| } |
| |
| @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(final RefEntity element) { |
| for (RefEntity entity : getIgnoredElements().keySet()) { |
| if (Comparing.equal(entity, element)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isProblemResolved(RefEntity refEntity, CommonProblemDescriptor descriptor) { |
| if (descriptor == null) return true; |
| for (RefEntity entity : getIgnoredElements().keySet()) { |
| if (Comparing.equal(entity, refEntity)) { |
| final CommonProblemDescriptor[] descriptors = getIgnoredElements().get(refEntity); |
| return ArrayUtil.contains(descriptor, descriptors); |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| @NotNull |
| public FileStatus getProblemStatus(@NotNull final CommonProblemDescriptor descriptor) { |
| final GlobalInspectionContextImpl context = getContext(); |
| if (!isDisposed() && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ |
| if (myOldProblemElements != null){ |
| final Set<CommonProblemDescriptor> allAvailable = new HashSet<CommonProblemDescriptor>(); |
| for (CommonProblemDescriptor[] descriptors : myOldProblemElements.values()) { |
| if (descriptors != null) { |
| ContainerUtil.addAll(allAvailable, descriptors); |
| } |
| } |
| final boolean old = containsDescriptor(descriptor, allAvailable); |
| final boolean current = containsDescriptor(descriptor, getProblemToElements().keySet()); |
| return calcStatus(old, current); |
| } |
| } |
| return FileStatus.NOT_CHANGED; |
| } |
| |
| private static boolean containsDescriptor(@NotNull CommonProblemDescriptor descriptor, Collection<CommonProblemDescriptor> descriptors){ |
| PsiElement element = null; |
| if (descriptor instanceof ProblemDescriptor){ |
| element = ((ProblemDescriptor)descriptor).getPsiElement(); |
| } |
| for (CommonProblemDescriptor problemDescriptor : descriptors) { |
| if (problemDescriptor instanceof ProblemDescriptor){ |
| if (!Comparing.equal(element, ((ProblemDescriptor)problemDescriptor).getPsiElement())){ |
| continue; |
| } |
| } |
| if (Comparing.strEqual(problemDescriptor.getDescriptionTemplate(), descriptor.getDescriptionTemplate())){ |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| @NotNull |
| @Override |
| public FileStatus getElementStatus(final RefEntity element) { |
| final GlobalInspectionContextImpl context = getContext(); |
| if (!isDisposed() && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ |
| if (myOldProblemElements != null){ |
| final boolean old = RefUtil.contains(element, myOldProblemElements.keySet()); |
| final boolean current = RefUtil.contains(element, getProblemElements().keySet()); |
| return calcStatus(old, current); |
| } |
| } |
| return FileStatus.NOT_CHANGED; |
| } |
| |
| @NotNull |
| @Override |
| public Collection<RefEntity> getIgnoredRefElements() { |
| return getIgnoredElements().keySet(); |
| } |
| |
| @Override |
| @NotNull |
| public Map<RefEntity, CommonProblemDescriptor[]> getProblemElements() { |
| synchronized (lock) { |
| if (myProblemElements == null) { |
| myProblemElements = Collections.synchronizedMap(new THashMap<RefEntity, CommonProblemDescriptor[]>()); |
| } |
| return myProblemElements; |
| } |
| } |
| |
| @Override |
| @Nullable |
| public Map<RefEntity, CommonProblemDescriptor[]> getOldProblemElements() { |
| return myOldProblemElements; |
| } |
| |
| @NotNull |
| private Map<CommonProblemDescriptor, RefEntity> getProblemToElements() { |
| synchronized (lock) { |
| if (myProblemToElements == null) { |
| myProblemToElements = Collections.synchronizedMap(new THashMap<CommonProblemDescriptor, RefEntity>()); |
| } |
| return myProblemToElements; |
| } |
| } |
| |
| @NotNull |
| private Map<RefEntity, Set<QuickFix>> getQuickFixActions() { |
| synchronized (lock) { |
| if (myQuickFixActions == null) { |
| myQuickFixActions = Collections.synchronizedMap(new com.intellij.util.containers.HashMap<RefEntity, Set<QuickFix>>()); |
| } |
| return myQuickFixActions; |
| } |
| } |
| |
| @NotNull |
| private Map<RefEntity, CommonProblemDescriptor[]> getIgnoredElements() { |
| synchronized (lock) { |
| if (myIgnoredElements == null) { |
| myIgnoredElements = Collections.synchronizedMap(new com.intellij.util.containers.HashMap<RefEntity, CommonProblemDescriptor[]>()); |
| } |
| return myIgnoredElements; |
| } |
| } |
| |
| @NotNull |
| @Override |
| public InspectionNode createToolNode(@NotNull GlobalInspectionContextImpl globalInspectionContext, @NotNull InspectionNode node, |
| @NotNull InspectionRVContentProvider provider, |
| @NotNull InspectionTreeNode parentNode, |
| boolean showStructure) { |
| return node; |
| } |
| |
| |
| @Override |
| @Nullable |
| public IntentionAction findQuickFixes(@NotNull final CommonProblemDescriptor problemDescriptor, final String hint) { |
| InspectionProfileEntry tool = getToolWrapper().getTool(); |
| if (!(tool instanceof GlobalInspectionTool)) return null; |
| final QuickFix fix = ((GlobalInspectionTool)tool).getQuickFix(hint); |
| if (fix == null) { |
| return null; |
| } |
| if (problemDescriptor instanceof ProblemDescriptor) { |
| final ProblemDescriptor descriptor = new ProblemDescriptorImpl(((ProblemDescriptor)problemDescriptor).getStartElement(), |
| ((ProblemDescriptor)problemDescriptor).getEndElement(), |
| problemDescriptor.getDescriptionTemplate(), |
| new LocalQuickFix[]{(LocalQuickFix)fix}, |
| ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false, null, false); |
| return QuickFixWrapper.wrap(descriptor, 0); |
| } |
| return new IntentionAction() { |
| @Override |
| @NotNull |
| public String getText() { |
| return fix.getName(); |
| } |
| |
| @Override |
| @NotNull |
| public String getFamilyName() { |
| return fix.getFamilyName(); |
| } |
| |
| @Override |
| public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { |
| return true; |
| } |
| |
| @Override |
| public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { |
| fix.applyFix(project, problemDescriptor); //todo check type consistency |
| } |
| |
| @Override |
| public boolean startInWriteAction() { |
| return true; |
| } |
| }; |
| } |
| |
| public static void setOutputPath(final String output) { |
| ourOutputPath = output; |
| } |
| } |