diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index f693233e86df..dfe27cfa5f79 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -56,6 +56,7 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.util.CommonProcessors; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Processor; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.SmartHashSet; import com.intellij.util.containers.TransferToEDTQueue; @@ -339,12 +340,20 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass } } + private static final TextAttributes NONEMPTY_TEXT_ATTRIBUTES = new TextAttributes() { + @Override + public boolean isEmpty() { + return false; + } + }; + @Nullable private HighlightInfo highlightInfoFromDescriptor(@NotNull ProblemDescriptor problemDescriptor, @NotNull HighlightInfoType highlightInfoType, @NotNull String message, String toolTip, - PsiElement psiElement) { + PsiElement psiElement, + @NotNull List quickFixes) { TextRange textRange = ((ProblemDescriptorBase)problemDescriptor).getTextRange(); if (textRange == null || psiElement == null) return null; boolean isFileLevel = psiElement instanceof PsiFile && textRange.equals(psiElement.getTextRange()); @@ -356,6 +365,11 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass .description(message) .severity(severity); if (toolTip != null) b.escapedToolTip(toolTip); + if (HighlightSeverity.INFORMATION.equals(severity) && attributes == null && toolTip == null && !quickFixes.isEmpty()) { + // Hack to avoid filtering this info out in HighlightInfoFilterImpl even though its attributes are empty. + // But it has quick fixes so it needs to be created. + attributes = NONEMPTY_TEXT_ATTRIBUTES; + } if (attributes != null) b.textAttributes(attributes); if (problemDescriptor.isAfterEndOfLine()) b.endOfLine(); if (isFileLevel) b.fileLevelAnnotation(); @@ -495,7 +509,6 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass } boolean isInjected = file != getFile(); if (!isInjected) { - outInfos.add(info); return; } @@ -518,7 +531,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass HighlightInfo patched = builder.createUnconditionally(); if (patched.startOffset != patched.endOffset || info.startOffset == info.endOffset) { patched.setFromInjection(true); - registerQuickFixes(toolWrapper, descriptor, patched, emptyActionRegistered); + registerQuickFixes(toolWrapper, patched, getQuickFixes(toolWrapper, descriptor, emptyActionRegistered)); outInfos.add(patched); } } @@ -554,40 +567,51 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass if (descriptor.showTooltip()) { tooltip = XmlStringUtil.wrapInHtml((message.startsWith("") ? XmlStringUtil.stripHtml(message): XmlStringUtil.escapeString(message)) + link); } - HighlightInfo highlightInfo = highlightInfoFromDescriptor(descriptor, type, plainMessage, tooltip,element); - if (highlightInfo != null) { - registerQuickFixes(tool, descriptor, highlightInfo, emptyActionRegistered); + List quickFixes = getQuickFixes(tool, descriptor, emptyActionRegistered); + HighlightInfo info = highlightInfoFromDescriptor(descriptor, type, plainMessage, tooltip, element, quickFixes); + if (info != null) { + registerQuickFixes(tool, info, quickFixes); } - return highlightInfo; + return info; } private static void registerQuickFixes(@NotNull LocalInspectionToolWrapper tool, - @NotNull ProblemDescriptor descriptor, @NotNull HighlightInfo highlightInfo, - @NotNull Set> emptyActionRegistered) { + @NotNull List quickFixes) { final HighlightDisplayKey key = HighlightDisplayKey.find(tool.getShortName()); + for (IntentionAction quickFix : quickFixes) { + QuickFixAction.registerQuickFixAction(highlightInfo, quickFix, key); + } + } + + private static List getQuickFixes(@NotNull LocalInspectionToolWrapper tool, + @NotNull ProblemDescriptor descriptor, + @NotNull Set> emptyActionRegistered) { + List result = new SmartList<>(); boolean needEmptyAction = true; final QuickFix[] fixes = descriptor.getFixes(); - if (fixes != null && fixes.length > 0) { + if (fixes != null && fixes.length != 0) { for (int k = 0; k < fixes.length; k++) { - if (fixes[k] != null) { // prevent null fixes from var args - QuickFixAction.registerQuickFixAction(highlightInfo, QuickFixWrapper.wrap(descriptor, k), key); - needEmptyAction = false; - } + QuickFix fix = fixes[k]; + if (fix == null) throw new IllegalStateException("Inspection " + tool + " returns null quick fix in its descriptor: " + descriptor + "; array: " + + Arrays.toString(fixes)); + result.add(QuickFixWrapper.wrap(descriptor, k)); + needEmptyAction = false; } } HintAction hintAction = descriptor instanceof ProblemDescriptorImpl ? ((ProblemDescriptorImpl)descriptor).getHintAction() : null; if (hintAction != null) { - QuickFixAction.registerQuickFixAction(highlightInfo, hintAction, key); + result.add(hintAction); needEmptyAction = false; } if (((ProblemDescriptorBase)descriptor).getEnforcedTextAttributes() != null) { needEmptyAction = false; } - if (needEmptyAction && emptyActionRegistered.add(Pair.create(highlightInfo.getFixTextRange(), tool.getShortName()))) { + if (needEmptyAction && emptyActionRegistered.add(Pair.create(((ProblemDescriptorBase)descriptor).getTextRange(), tool.getShortName()))) { IntentionAction emptyIntentionAction = new EmptyIntentionAction(tool.getDisplayName()); - QuickFixAction.registerQuickFixAction(highlightInfo, emptyIntentionAction, key); + result.add(emptyIntentionAction); } + return result; } private static void getElementsAndDialectsFrom(@NotNull PsiFile file,