2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.intellij
.codeInsight
.daemon
.impl
;
19 import com
.intellij
.codeHighlighting
.Pass
;
20 import com
.intellij
.codeInsight
.daemon
.DaemonBundle
;
21 import com
.intellij
.codeInsight
.daemon
.HighlightDisplayKey
;
22 import com
.intellij
.codeInsight
.daemon
.impl
.analysis
.HighlightLevelUtil
;
23 import com
.intellij
.codeInsight
.daemon
.impl
.quickfix
.QuickFixAction
;
24 import com
.intellij
.codeInsight
.intention
.EmptyIntentionAction
;
25 import com
.intellij
.codeInspection
.*;
26 import com
.intellij
.codeInspection
.ex
.*;
27 import com
.intellij
.concurrency
.JobUtil
;
28 import com
.intellij
.injected
.editor
.DocumentWindow
;
29 import com
.intellij
.lang
.Language
;
30 import com
.intellij
.lang
.annotation
.HighlightSeverity
;
31 import com
.intellij
.lang
.injection
.InjectedLanguageManager
;
32 import com
.intellij
.openapi
.actionSystem
.IdeActions
;
33 import com
.intellij
.openapi
.application
.ApplicationManager
;
34 import com
.intellij
.openapi
.diagnostic
.Logger
;
35 import com
.intellij
.openapi
.editor
.Document
;
36 import com
.intellij
.openapi
.editor
.colors
.CodeInsightColors
;
37 import com
.intellij
.openapi
.editor
.colors
.TextAttributesKey
;
38 import com
.intellij
.openapi
.keymap
.Keymap
;
39 import com
.intellij
.openapi
.keymap
.KeymapManager
;
40 import com
.intellij
.openapi
.keymap
.KeymapUtil
;
41 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
42 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
43 import com
.intellij
.openapi
.progress
.ProgressManager
;
44 import com
.intellij
.openapi
.project
.DumbAware
;
45 import com
.intellij
.openapi
.project
.DumbService
;
46 import com
.intellij
.openapi
.util
.IconLoader
;
47 import com
.intellij
.openapi
.util
.TextRange
;
48 import com
.intellij
.openapi
.util
.text
.StringUtil
;
49 import com
.intellij
.profile
.codeInspection
.InspectionProjectProfileManager
;
50 import com
.intellij
.psi
.*;
51 import com
.intellij
.psi
.impl
.source
.tree
.injected
.InjectedLanguageUtil
;
52 import com
.intellij
.util
.Processor
;
53 import com
.intellij
.util
.SmartList
;
54 import com
.intellij
.util
.containers
.ContainerUtil
;
55 import com
.intellij
.xml
.util
.XmlStringUtil
;
56 import gnu
.trove
.THashMap
;
57 import gnu
.trove
.THashSet
;
58 import org
.jetbrains
.annotations
.NonNls
;
59 import org
.jetbrains
.annotations
.NotNull
;
60 import org
.jetbrains
.annotations
.Nullable
;
68 public class LocalInspectionsPass
extends ProgressableTextEditorHighlightingPass
implements DumbAware
{
69 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.daemon.impl.LocalInspectionsPass");
70 private final int myStartOffset
;
71 private final int myEndOffset
;
72 @NotNull private List
<ProblemDescriptor
> myDescriptors
= Collections
.emptyList();
73 @NotNull private List
<HighlightInfoType
> myLevels
= Collections
.emptyList();
74 @NotNull private List
<LocalInspectionTool
> myTools
= Collections
.emptyList();
75 @NotNull private List
<InjectedPsiInspectionResult
> myInjectedPsiInspectionResults
= Collections
.emptyList();
76 static final String PRESENTABLE_NAME
= DaemonBundle
.message("pass.inspection");
77 private volatile List
<HighlightInfo
> myInfos
= Collections
.emptyList();
78 static final Icon IN_PROGRESS_ICON
= IconLoader
.getIcon("/general/inspectionInProgress.png");
79 private final String myShortcutText
;
80 private final SeverityRegistrar mySeverityRegistrar
;
82 public LocalInspectionsPass(@NotNull PsiFile file
, @Nullable Document document
, int startOffset
, int endOffset
) {
83 super(file
.getProject(), document
, IN_PROGRESS_ICON
, PRESENTABLE_NAME
, file
, true);
84 myStartOffset
= startOffset
;
85 myEndOffset
= endOffset
;
86 setId(Pass
.LOCAL_INSPECTIONS
);
88 final KeymapManager keymapManager
= KeymapManager
.getInstance();
89 if (keymapManager
!= null) {
90 final Keymap keymap
= keymapManager
.getActiveKeymap();
91 myShortcutText
= keymap
== null ?
"" : "(" + KeymapUtil
.getShortcutsText(keymap
.getShortcuts(IdeActions
.ACTION_SHOW_ERROR_DESCRIPTION
)) + ")";
96 mySeverityRegistrar
= SeverityRegistrar
.getInstance(myProject
);
99 protected void collectInformationWithProgress(final ProgressIndicator progress
) {
100 myDescriptors
= new ArrayList
<ProblemDescriptor
>();
101 myLevels
= new ArrayList
<HighlightInfoType
>();
102 myTools
= new ArrayList
<LocalInspectionTool
>();
103 long startTime
= System
.nanoTime();
105 long endTime
= System
.nanoTime();
106 if (LOG
.isDebugEnabled()) {
107 LOG
.debug("Inspections for " + myFile
.getName() + " completed in " + (endTime
- startTime
) / 1000000 + " ms");
111 private void inspectRoot() {
112 if (!HighlightLevelUtil
.shouldInspect(myFile
)) return;
113 final InspectionManagerEx iManager
= (InspectionManagerEx
)InspectionManager
.getInstance(myProject
);
114 final InspectionProfileWrapper profile
= InspectionProjectProfileManager
.getInstance(myProject
).getProfileWrapper();
115 final List
<LocalInspectionTool
> tools
= DumbService
.getInstance(myProject
).filterByDumbAwareness(getInspectionTools(profile
));
117 inspect(tools
, iManager
, true, true);
120 public void doInspectInBatch(final InspectionManagerEx iManager
, InspectionProfileEntry
[] toolWrappers
, boolean ignoreSuppressed
) {
121 myDescriptors
= new ArrayList
<ProblemDescriptor
>();
122 myLevels
= new ArrayList
<HighlightInfoType
>();
123 myTools
= new ArrayList
<LocalInspectionTool
>();
125 Map
<LocalInspectionTool
, LocalInspectionToolWrapper
> tool2Wrapper
= new THashMap
<LocalInspectionTool
, LocalInspectionToolWrapper
>(toolWrappers
.length
);
126 for (InspectionProfileEntry toolWrapper
: toolWrappers
) {
127 tool2Wrapper
.put(((LocalInspectionToolWrapper
)toolWrapper
).getTool(), (LocalInspectionToolWrapper
)toolWrapper
);
129 List
<LocalInspectionTool
> tools
= new ArrayList
<LocalInspectionTool
>(tool2Wrapper
.keySet());
130 inspect(tools
, iManager
, false, ignoreSuppressed
);
131 addDescriptorsFromInjectedResults(tool2Wrapper
, iManager
);
132 for (int i
= 0; i
< myTools
.size(); i
++) {
133 final LocalInspectionTool tool
= myTools
.get(i
);
134 ProblemDescriptor descriptor
= myDescriptors
.get(i
);
135 LocalInspectionToolWrapper toolWrapper
= tool2Wrapper
.get(tool
);
137 toolWrapper
.addProblemDescriptors(Collections
.singletonList(descriptor
), true);
141 private void addDescriptorsFromInjectedResults(Map
<LocalInspectionTool
, LocalInspectionToolWrapper
> tool2Wrapper
,
142 InspectionManagerEx iManager
) {
143 Set
<TextRange
> emptyActionRegistered
= new THashSet
<TextRange
>();
144 InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
145 InjectedLanguageManager ilManager
= InjectedLanguageManager
.getInstance(myProject
);
146 PsiDocumentManager documentManager
= PsiDocumentManager
.getInstance(myProject
);
147 //noinspection ForLoopReplaceableByForEach
148 for (int i
= 0; i
< myInjectedPsiInspectionResults
.size(); i
++) {
149 InjectedPsiInspectionResult result
= myInjectedPsiInspectionResults
.get(i
);
150 LocalInspectionTool tool
= result
.tool
;
151 HighlightSeverity severity
= inspectionProfile
.getErrorLevel(HighlightDisplayKey
.find(tool
.getShortName()), myFile
).getSeverity();
153 PsiElement injectedPsi
= result
.injectedPsi
;
154 DocumentWindow documentRange
= (DocumentWindow
)documentManager
.getDocument((PsiFile
)injectedPsi
);
155 if (documentRange
== null) continue;
156 //noinspection ForLoopReplaceableByForEach
157 for (int j
= 0; j
< result
.foundProblems
.size(); j
++) {
158 ProblemDescriptor descriptor
= result
.foundProblems
.get(j
);
159 PsiElement psiElement
= descriptor
.getPsiElement();
160 if (InspectionManagerEx
.inspectionResultSuppressed(psiElement
, tool
)) continue;
161 HighlightInfoType level
= highlightTypeFromDescriptor(descriptor
, severity
);
162 HighlightInfo info
= createHighlightInfo(descriptor
, tool
, level
,emptyActionRegistered
);
163 if (info
== null) continue;
164 List
<TextRange
> editables
= ilManager
.intersectWithAllEditableFragments((PsiFile
)injectedPsi
, new TextRange(info
.startOffset
, info
.endOffset
));
165 for (TextRange editable
: editables
) {
166 TextRange hostRange
= documentRange
.injectedToHost(editable
);
167 QuickFix
[] fixes
= descriptor
.getFixes();
168 LocalQuickFix
[] localFixes
= null;
170 localFixes
= new LocalQuickFix
[fixes
.length
];
171 for (int k
= 0; k
< fixes
.length
; k
++) {
172 QuickFix fix
= fixes
[k
];
173 localFixes
[k
] = (LocalQuickFix
)fix
;
176 ProblemDescriptor patchedDescriptor
= iManager
.createProblemDescriptor(myFile
, hostRange
, descriptor
.getDescriptionTemplate(),
177 descriptor
.getHighlightType(),
179 LocalInspectionToolWrapper toolWrapper
= tool2Wrapper
.get(tool
);
180 toolWrapper
.addProblemDescriptors(Collections
.singletonList(patchedDescriptor
), true);
186 private void inspect(final List
<LocalInspectionTool
> tools
, final InspectionManagerEx iManager
, final boolean isOnTheFly
, final boolean ignoreSuppressed
) {
187 if (tools
.isEmpty()) return;
188 final PsiElement
[] elements
= getElementsIntersectingRange(myFile
, myStartOffset
, myEndOffset
);
190 setProgressLimit(1L * tools
.size() * elements
.length
);
191 final LocalInspectionToolSession session
= new LocalInspectionToolSession(myFile
, myStartOffset
, myEndOffset
);
193 JobUtil
.invokeConcurrentlyUnderMyProgress(tools
, new Processor
<LocalInspectionTool
>() {
194 public boolean process(final LocalInspectionTool tool
) {
195 final ProgressManager progressManager
= ProgressManager
.getInstance();
197 progressManager
.checkCanceled();
199 ApplicationManager
.getApplication().assertReadAccessAllowed();
201 ProblemsHolder holder
= new ProblemsHolder(iManager
, myFile
);
202 progressManager
.checkCanceled();
203 PsiElementVisitor elementVisitor
= tool
.buildVisitor(holder
, isOnTheFly
);
204 //noinspection ConstantConditions
205 if(elementVisitor
== null) {
206 LOG
.error("Tool " + tool
+ " must not return null from the buildVisitor() method");
208 tool
.inspectionStarted(session
);
209 for (PsiElement element
: elements
) {
210 progressManager
.checkCanceled();
211 element
.accept(elementVisitor
);
213 tool
.inspectionFinished(session
);
214 advanceProgress(elements
.length
);
216 if (holder
.hasResults()) {
217 appendDescriptors(holder
.getResults(), tool
, ignoreSuppressed
);
221 catch (ProcessCanceledException e
) {
225 }, "Inspection tools");
227 inspectInjectedPsi(elements
, tools
);
229 myInfos
= new ArrayList
<HighlightInfo
>(myDescriptors
.size());
230 addHighlightsFromDescriptors(myInfos
);
231 addHighlightsFromInjectedPsiProblems(myInfos
);
234 void inspectInjectedPsi(final PsiElement
[] elements
, final List
<LocalInspectionTool
> tools
) {
235 myInjectedPsiInspectionResults
= ContainerUtil
.createEmptyCOWList();
236 final Set
<PsiFile
> injected
= new THashSet
<PsiFile
>();
237 for (PsiElement element
: elements
) {
238 InjectedLanguageUtil
.enumerate(element
, myFile
, new PsiLanguageInjectionHost
.InjectedPsiVisitor() {
239 public void visit(@NotNull PsiFile injectedPsi
, @NotNull List
<PsiLanguageInjectionHost
.Shred
> places
) {
240 injected
.add(injectedPsi
);
244 JobUtil
.invokeConcurrentlyUnderMyProgress(injected
, new Processor
<PsiFile
>() {
245 public boolean process(final PsiFile injectedPsi
) {
246 inspectInjectedPsi(injectedPsi
, myInjectedPsiInspectionResults
, tools
);
249 }, "Inspect injected fragments");
252 public Collection
<HighlightInfo
> getHighlights() {
253 ArrayList
<HighlightInfo
> highlights
= new ArrayList
<HighlightInfo
>(myDescriptors
.size());
254 addHighlightsFromDescriptors(highlights
);
255 addHighlightsFromInjectedPsiProblems(highlights
);
259 private static HighlightInfo
highlightInfoFromDescriptor(final ProblemDescriptor problemDescriptor
,
260 final HighlightInfoType highlightInfoType
,
261 final String message
,
262 final String toolTip
) {
263 TextRange textRange
= ((ProblemDescriptorImpl
)problemDescriptor
).getTextRange();
264 PsiElement element
= problemDescriptor
.getPsiElement();
265 boolean isFileLevel
= element
instanceof PsiFile
&& textRange
.equals(element
.getTextRange());
266 HighlightInfo highlightInfo
= new HighlightInfo(null, highlightInfoType
, textRange
.getStartOffset(), textRange
.getEndOffset(), message
,
267 toolTip
, highlightInfoType
.getSeverity(element
), problemDescriptor
.isAfterEndOfLine(), null,
270 return highlightInfo
;
273 private synchronized void appendDescriptors(List
<ProblemDescriptor
> problemDescriptors
, LocalInspectionTool tool
, boolean ignoreSuppressed
) {
274 if (problemDescriptors
== null) return;
275 InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
276 final HighlightSeverity severity
= inspectionProfile
.getErrorLevel(HighlightDisplayKey
.find(tool
.getShortName()), myFile
).getSeverity();
277 ProgressManager progressManager
= ProgressManager
.getInstance();
278 for (ProblemDescriptor problemDescriptor
: problemDescriptors
) {
279 progressManager
.checkCanceled();
280 if (!(ignoreSuppressed
&& InspectionManagerEx
.inspectionResultSuppressed(problemDescriptor
.getPsiElement(), tool
))) {
281 myDescriptors
.add(problemDescriptor
);
282 HighlightInfoType type
= highlightTypeFromDescriptor(problemDescriptor
, severity
);
290 private HighlightInfoType
highlightTypeFromDescriptor(final ProblemDescriptor problemDescriptor
, final HighlightSeverity severity
) {
291 final ProblemHighlightType highlightType
= problemDescriptor
.getHighlightType();
292 switch (highlightType
) {
293 case GENERIC_ERROR_OR_WARNING
:
294 return mySeverityRegistrar
.getHighlightInfoTypeBySeverity(severity
);
295 case LIKE_DEPRECATED
:
296 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, HighlightInfoType
.DEPRECATED
.getAttributesKey());
297 case LIKE_UNKNOWN_SYMBOL
:
298 if (severity
== HighlightSeverity
.ERROR
) {
299 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, HighlightInfoType
.WRONG_REF
.getAttributesKey());
301 else if (severity
== HighlightSeverity
.WARNING
) {
302 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, CodeInsightColors
.INFO_ATTRIBUTES
);
305 return mySeverityRegistrar
.getHighlightInfoTypeBySeverity(severity
);
307 case LIKE_UNUSED_SYMBOL
:
308 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, HighlightInfoType
.UNUSED_SYMBOL
.getAttributesKey());
310 return HighlightInfoType
.INFO
;
312 return HighlightInfoType
.WRONG_REF
;
314 return HighlightInfoType
.ERROR
;
316 final TextAttributesKey attributes
= ((ProblemDescriptorImpl
)problemDescriptor
).getEnforcedTextAttributes();
317 if (attributes
!= null) {
318 return new HighlightInfoType
.HighlightInfoTypeImpl(HighlightSeverity
.INFORMATION
, attributes
);
320 return HighlightInfoType
.INFORMATION
;
322 throw new RuntimeException("Cannot map " + highlightType
);
325 protected void applyInformationWithProgress() {
326 UpdateHighlightersUtil
.setHighlightersToEditor(myProject
, myDocument
, myStartOffset
, myEndOffset
, myInfos
, getId());
329 private void addHighlightsFromDescriptors(final List
<HighlightInfo
> toInfos
) {
330 Set
<TextRange
> emptyActionRegistered
= new THashSet
<TextRange
>();
331 for (int i
= 0; i
< myDescriptors
.size(); i
++) {
332 ProblemDescriptor descriptor
= myDescriptors
.get(i
);
333 LocalInspectionTool tool
= myTools
.get(i
);
334 final HighlightInfoType level
= myLevels
.get(i
);
335 HighlightInfo highlightInfo
= createHighlightInfo(descriptor
, tool
, level
, emptyActionRegistered
);
336 if (highlightInfo
!= null) {
337 toInfos
.add(highlightInfo
);
342 private void addHighlightsFromInjectedPsiProblems(final List
<HighlightInfo
> infos
) {
343 Set
<TextRange
> emptyActionRegistered
= new THashSet
<TextRange
>();
344 InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
345 PsiDocumentManager documentManager
= PsiDocumentManager
.getInstance(myProject
);
346 InjectedLanguageManager ilManager
= InjectedLanguageManager
.getInstance(myProject
);
347 for (InjectedPsiInspectionResult result
: myInjectedPsiInspectionResults
) {
348 LocalInspectionTool tool
= result
.tool
;
349 HighlightSeverity severity
= inspectionProfile
.getErrorLevel(HighlightDisplayKey
.find(tool
.getShortName()), myFile
).getSeverity();
351 PsiElement injectedPsi
= result
.injectedPsi
;
352 DocumentWindow documentRange
= (DocumentWindow
)documentManager
.getDocument((PsiFile
)injectedPsi
);
353 if (documentRange
== null) continue;
354 //noinspection ForLoopReplaceableByForEach
355 for (int j
= 0; j
< result
.foundProblems
.size(); j
++) {
356 ProblemDescriptor descriptor
= result
.foundProblems
.get(j
);
357 PsiElement psiElement
= descriptor
.getPsiElement();
358 if (InspectionManagerEx
.inspectionResultSuppressed(psiElement
, tool
)) continue;
359 HighlightInfoType level
= highlightTypeFromDescriptor(descriptor
, severity
);
360 HighlightInfo info
= createHighlightInfo(descriptor
, tool
, level
, emptyActionRegistered
);
361 if (info
== null) continue;
363 // todo we got to separate our "internal" prefixes/suffixes from user-defined ones
364 // todo in the latter case the erors should be highlighted, otherwise not
365 List
<TextRange
> editables
=
366 ilManager
.intersectWithAllEditableFragments((PsiFile
)injectedPsi
, new TextRange(info
.startOffset
, info
.endOffset
));
367 for (TextRange editable
: editables
) {
368 TextRange hostRange
= documentRange
.injectedToHost(editable
);
369 HighlightInfo patched
= HighlightInfo
.createHighlightInfo(info
.type
, psiElement
, hostRange
.getStartOffset(), hostRange
.getEndOffset(), info
.description
, info
.toolTip
);
370 if (patched
!= null) {
371 registerQuickFixes(tool
, descriptor
, patched
, emptyActionRegistered
);
380 private HighlightInfo
createHighlightInfo(final ProblemDescriptor descriptor
, final LocalInspectionTool tool
, final HighlightInfoType level
,
381 final Set
<TextRange
> emptyActionRegistered
) {
382 PsiElement psiElement
= descriptor
.getPsiElement();
383 if (psiElement
== null) return null;
384 @NonNls String message
= renderDescriptionMessage(descriptor
);
386 final HighlightDisplayKey key
= HighlightDisplayKey
.find(tool
.getShortName());
387 final InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
388 if (!inspectionProfile
.isToolEnabled(key
, myFile
)) return null;
390 HighlightInfoType type
= new HighlightInfoType
.HighlightInfoTypeImpl(level
.getSeverity(psiElement
), level
.getAttributesKey());
391 final String plainMessage
= message
.startsWith("<html>") ? StringUtil
.unescapeXml(message
.replaceAll("<[^>]*>", "")) : message
;
392 @NonNls final String link
= "<a href=\"#inspection/" + tool
.getShortName() + "\"> " + DaemonBundle
.message("inspection.extended.description") +
393 "</a>" + myShortcutText
;
395 @NonNls String tooltip
;
396 if (message
.startsWith("<html>")) {
397 tooltip
= message
.contains("</body>") ? message
.replace("</body>", link
+ "</body>") : message
.replace("</html>", link
+ "</html>");
400 tooltip
= "<html><body>" + XmlStringUtil
.escapeString(message
) + link
+ "</body></html>";
402 HighlightInfo highlightInfo
= highlightInfoFromDescriptor(descriptor
, type
, plainMessage
, tooltip
);
403 registerQuickFixes(tool
, descriptor
, highlightInfo
, emptyActionRegistered
);
404 return highlightInfo
;
407 private static void registerQuickFixes(final LocalInspectionTool tool
, final ProblemDescriptor descriptor
,
408 final HighlightInfo highlightInfo
, final Set
<TextRange
> emptyActionRegistered
) {
409 final HighlightDisplayKey key
= HighlightDisplayKey
.find(tool
.getShortName());
410 boolean needEmptyAction
= true;
411 final QuickFix
[] fixes
= descriptor
.getFixes();
412 if (fixes
!= null && fixes
.length
> 0) {
413 for (int k
= 0; k
< fixes
.length
; k
++) {
414 if (fixes
[k
] != null) { // prevent null fixes from var args
415 QuickFixAction
.registerQuickFixAction(highlightInfo
, QuickFixWrapper
.wrap(descriptor
, k
), key
);
416 needEmptyAction
= false;
420 HintAction hintAction
= ((ProblemDescriptorImpl
)descriptor
).getHintAction();
421 if (hintAction
!= null) {
422 QuickFixAction
.registerQuickFixAction(highlightInfo
, hintAction
, key
);
423 needEmptyAction
= false;
425 if (((ProblemDescriptorImpl
)descriptor
).getEnforcedTextAttributes() != null) {
426 needEmptyAction
= false;
428 if (needEmptyAction
&& emptyActionRegistered
.add(new TextRange(highlightInfo
.fixStartOffset
, highlightInfo
.fixEndOffset
))) {
429 EmptyIntentionAction emptyIntentionAction
= new EmptyIntentionAction(tool
.getDisplayName());
430 QuickFixAction
.registerQuickFixAction(highlightInfo
, emptyIntentionAction
, key
);
434 private static String
renderDescriptionMessage(ProblemDescriptor descriptor
) {
435 PsiElement psiElement
= descriptor
.getPsiElement();
436 String message
= descriptor
.getDescriptionTemplate();
438 // no message. Should not be the case if inspection correctly implemented.
439 // noinspection ConstantConditions
440 if (message
== null) return "";
442 message
= StringUtil
.replace(message
, "<code>", "'");
443 message
= StringUtil
.replace(message
, "</code>", "'");
444 //message = message.replaceAll("<[^>]*>", "");
445 String text
= psiElement
== null ?
"" : psiElement
.getText();
446 message
= StringUtil
.replace(message
, "#loc", "");
447 message
= StringUtil
.replace(message
, "#ref", text
);
449 message
= StringUtil
.unescapeXml(message
).trim();
453 public static PsiElement
[] getElementsIntersectingRange(PsiFile file
, final int startOffset
, final int endOffset
) {
454 final FileViewProvider viewProvider
= file
.getViewProvider();
455 final Set
<PsiElement
> result
= new LinkedHashSet
<PsiElement
>();
456 for (Language language
: viewProvider
.getLanguages()) {
457 final PsiFile psiRoot
= viewProvider
.getPsi(language
);
458 if (HighlightLevelUtil
.shouldInspect(psiRoot
)) {
459 result
.addAll(CollectHighlightsUtil
.getElementsInRange(psiRoot
, startOffset
, endOffset
, true));
462 return result
.toArray(new PsiElement
[result
.size()]);
465 List
<LocalInspectionTool
> getInspectionTools(InspectionProfileWrapper profile
) {
466 return profile
.getHighlightingLocalInspectionTools(myFile
);
469 private static void inspectInjectedPsi(PsiFile injectedPsi
, List
<InjectedPsiInspectionResult
> result
, List
<LocalInspectionTool
> tools
) {
470 InspectionManager inspectionManager
= InspectionManager
.getInstance(injectedPsi
.getProject());
471 final ProblemsHolder problemsHolder
= new ProblemsHolder(inspectionManager
, injectedPsi
);
472 final PsiElement host
= injectedPsi
.getContext();
473 for (LocalInspectionTool tool
: tools
) {
474 if (host
!= null && InspectionManagerEx
.inspectionResultSuppressed(host
, tool
)) {
477 final PsiElementVisitor visitor
= tool
.buildVisitor(problemsHolder
, true);
478 assert !(visitor
instanceof PsiRecursiveElementVisitor
) : "The visitor returned from LocalInspectionTool.buildVisitor() must not be recursive. "+tool
;
479 injectedPsi
.accept(new PsiRecursiveElementWalkingVisitor() {
480 @Override public void visitElement(PsiElement element
) {
481 element
.accept(visitor
);
482 super.visitElement(element
);
485 List
<ProblemDescriptor
> problems
= problemsHolder
.getResults();
486 if (problems
!= null && !problems
.isEmpty()) {
487 InjectedPsiInspectionResult res
= new InjectedPsiInspectionResult(tool
, injectedPsi
, new SmartList
<ProblemDescriptor
>(problems
));
493 public List
<HighlightInfo
> getInfos() {
497 private static class InjectedPsiInspectionResult
{
498 public final LocalInspectionTool tool
;
499 public final PsiElement injectedPsi
;
500 public final List
<ProblemDescriptor
> foundProblems
;
502 private InjectedPsiInspectionResult(final LocalInspectionTool tool
, final PsiElement injectedPsi
, final List
<ProblemDescriptor
> foundProblems
) {
504 this.injectedPsi
= injectedPsi
;
505 this.foundProblems
= foundProblems
;