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
.codeInspection
.ui
.ProblemDescriptionNode
;
28 import com
.intellij
.concurrency
.JobUtil
;
29 import com
.intellij
.injected
.editor
.DocumentWindow
;
30 import com
.intellij
.lang
.Language
;
31 import com
.intellij
.lang
.annotation
.HighlightSeverity
;
32 import com
.intellij
.lang
.injection
.InjectedLanguageManager
;
33 import com
.intellij
.openapi
.actionSystem
.IdeActions
;
34 import com
.intellij
.openapi
.application
.ApplicationManager
;
35 import com
.intellij
.openapi
.diagnostic
.Logger
;
36 import com
.intellij
.openapi
.editor
.Document
;
37 import com
.intellij
.openapi
.editor
.colors
.CodeInsightColors
;
38 import com
.intellij
.openapi
.editor
.colors
.TextAttributesKey
;
39 import com
.intellij
.openapi
.keymap
.Keymap
;
40 import com
.intellij
.openapi
.keymap
.KeymapManager
;
41 import com
.intellij
.openapi
.keymap
.KeymapUtil
;
42 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
43 import com
.intellij
.openapi
.progress
.ProgressManager
;
44 import com
.intellij
.openapi
.progress
.util
.ProgressWrapper
;
45 import com
.intellij
.openapi
.project
.DumbAware
;
46 import com
.intellij
.openapi
.project
.DumbService
;
47 import com
.intellij
.openapi
.util
.IconLoader
;
48 import com
.intellij
.openapi
.util
.TextRange
;
49 import com
.intellij
.openapi
.util
.text
.StringUtil
;
50 import com
.intellij
.profile
.codeInspection
.InspectionProjectProfileManager
;
51 import com
.intellij
.psi
.*;
52 import com
.intellij
.psi
.impl
.source
.tree
.injected
.InjectedLanguageUtil
;
53 import com
.intellij
.util
.Processor
;
54 import com
.intellij
.util
.SmartList
;
55 import com
.intellij
.util
.containers
.ContainerUtil
;
56 import com
.intellij
.xml
.util
.XmlStringUtil
;
57 import gnu
.trove
.THashMap
;
58 import gnu
.trove
.THashSet
;
59 import org
.jetbrains
.annotations
.NonNls
;
60 import org
.jetbrains
.annotations
.NotNull
;
61 import org
.jetbrains
.annotations
.Nullable
;
69 public class LocalInspectionsPass
extends ProgressableTextEditorHighlightingPass
implements DumbAware
{
70 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.daemon.impl.LocalInspectionsPass");
71 private final int myStartOffset
;
72 private final int myEndOffset
;
73 @NotNull private List
<ProblemDescriptor
> myDescriptors
= Collections
.emptyList();
74 @NotNull private List
<HighlightInfoType
> myLevels
= Collections
.emptyList();
75 @NotNull private List
<LocalInspectionTool
> myTools
= Collections
.emptyList();
76 @NotNull private List
<InjectedPsiInspectionResult
> myInjectedPsiInspectionResults
= Collections
.emptyList();
77 static final String PRESENTABLE_NAME
= DaemonBundle
.message("pass.inspection");
78 private volatile List
<HighlightInfo
> myInfos
= Collections
.emptyList();
79 static final Icon IN_PROGRESS_ICON
= IconLoader
.getIcon("/general/inspectionInProgress.png");
80 private final String myShortcutText
;
81 private final SeverityRegistrar mySeverityRegistrar
;
83 public LocalInspectionsPass(@NotNull PsiFile file
, @Nullable Document document
, int startOffset
, int endOffset
) {
84 super(file
.getProject(), document
, IN_PROGRESS_ICON
, PRESENTABLE_NAME
, file
, true);
85 myStartOffset
= startOffset
;
86 myEndOffset
= endOffset
;
87 setId(Pass
.LOCAL_INSPECTIONS
);
89 final KeymapManager keymapManager
= KeymapManager
.getInstance();
90 if (keymapManager
!= null) {
91 final Keymap keymap
= keymapManager
.getActiveKeymap();
92 myShortcutText
= keymap
== null ?
"" : "(" + KeymapUtil
.getShortcutsText(keymap
.getShortcuts(IdeActions
.ACTION_SHOW_ERROR_DESCRIPTION
)) + ")";
97 mySeverityRegistrar
= SeverityRegistrar
.getInstance(myProject
);
100 protected void collectInformationWithProgress(final ProgressIndicator progress
) {
101 myDescriptors
= new ArrayList
<ProblemDescriptor
>();
102 myLevels
= new ArrayList
<HighlightInfoType
>();
103 myTools
= new ArrayList
<LocalInspectionTool
>();
104 long startTime
= System
.nanoTime();
106 long endTime
= System
.nanoTime();
107 if (LOG
.isDebugEnabled()) {
108 LOG
.debug("Inspections for " + myFile
.getName() + " completed in " + (endTime
- startTime
) / 1000000 + " ms");
112 private void inspectRoot() {
113 if (!HighlightLevelUtil
.shouldInspect(myFile
)) return;
114 final InspectionManagerEx iManager
= (InspectionManagerEx
)InspectionManager
.getInstance(myProject
);
115 final InspectionProfileWrapper profile
= InspectionProjectProfileManager
.getInstance(myProject
).getProfileWrapper();
116 final List
<LocalInspectionTool
> tools
= DumbService
.getInstance(myProject
).filterByDumbAwareness(getInspectionTools(profile
));
118 inspect(tools
, iManager
, true, true);
121 public void doInspectInBatch(final InspectionManagerEx iManager
, InspectionProfileEntry
[] toolWrappers
, boolean ignoreSuppressed
) {
122 myDescriptors
= new ArrayList
<ProblemDescriptor
>();
123 myLevels
= new ArrayList
<HighlightInfoType
>();
124 myTools
= new ArrayList
<LocalInspectionTool
>();
126 Map
<LocalInspectionTool
, LocalInspectionToolWrapper
> tool2Wrapper
= new THashMap
<LocalInspectionTool
, LocalInspectionToolWrapper
>(toolWrappers
.length
);
127 for (InspectionProfileEntry toolWrapper
: toolWrappers
) {
128 tool2Wrapper
.put(((LocalInspectionToolWrapper
)toolWrapper
).getTool(), (LocalInspectionToolWrapper
)toolWrapper
);
130 List
<LocalInspectionTool
> tools
= new ArrayList
<LocalInspectionTool
>(tool2Wrapper
.keySet());
131 inspect(tools
, iManager
, false, ignoreSuppressed
);
132 addDescriptorsFromInjectedResults(tool2Wrapper
, iManager
);
133 for (int i
= 0; i
< myTools
.size(); i
++) {
134 final LocalInspectionTool tool
= myTools
.get(i
);
135 ProblemDescriptor descriptor
= myDescriptors
.get(i
);
136 LocalInspectionToolWrapper toolWrapper
= tool2Wrapper
.get(tool
);
138 toolWrapper
.addProblemDescriptors(Collections
.singletonList(descriptor
), true);
142 private void addDescriptorsFromInjectedResults(Map
<LocalInspectionTool
, LocalInspectionToolWrapper
> tool2Wrapper
,
143 InspectionManagerEx iManager
) {
144 Set
<TextRange
> emptyActionRegistered
= new THashSet
<TextRange
>();
145 InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
146 InjectedLanguageManager ilManager
= InjectedLanguageManager
.getInstance(myProject
);
147 PsiDocumentManager documentManager
= PsiDocumentManager
.getInstance(myProject
);
148 //noinspection ForLoopReplaceableByForEach
149 for (int i
= 0; i
< myInjectedPsiInspectionResults
.size(); i
++) {
150 InjectedPsiInspectionResult result
= myInjectedPsiInspectionResults
.get(i
);
151 LocalInspectionTool tool
= result
.tool
;
152 HighlightSeverity severity
= inspectionProfile
.getErrorLevel(HighlightDisplayKey
.find(tool
.getShortName()), myFile
).getSeverity();
154 PsiElement injectedPsi
= result
.injectedPsi
;
155 DocumentWindow documentRange
= (DocumentWindow
)documentManager
.getDocument((PsiFile
)injectedPsi
);
156 if (documentRange
== null) continue;
157 //noinspection ForLoopReplaceableByForEach
158 for (int j
= 0; j
< result
.foundProblems
.size(); j
++) {
159 ProblemDescriptor descriptor
= result
.foundProblems
.get(j
);
160 PsiElement psiElement
= descriptor
.getPsiElement();
161 if (InspectionManagerEx
.inspectionResultSuppressed(psiElement
, tool
)) continue;
162 HighlightInfoType level
= highlightTypeFromDescriptor(descriptor
, severity
);
163 HighlightInfo info
= createHighlightInfo(descriptor
, tool
, level
,emptyActionRegistered
);
164 if (info
== null) continue;
165 List
<TextRange
> editables
= ilManager
.intersectWithAllEditableFragments((PsiFile
)injectedPsi
, new TextRange(info
.startOffset
, info
.endOffset
));
166 for (TextRange editable
: editables
) {
167 TextRange hostRange
= documentRange
.injectedToHost(editable
);
168 QuickFix
[] fixes
= descriptor
.getFixes();
169 LocalQuickFix
[] localFixes
= null;
171 localFixes
= new LocalQuickFix
[fixes
.length
];
172 for (int k
= 0; k
< fixes
.length
; k
++) {
173 QuickFix fix
= fixes
[k
];
174 localFixes
[k
] = (LocalQuickFix
)fix
;
177 ProblemDescriptor patchedDescriptor
= iManager
.createProblemDescriptor(myFile
, hostRange
, descriptor
.getDescriptionTemplate(),
178 descriptor
.getHighlightType(),
180 LocalInspectionToolWrapper toolWrapper
= tool2Wrapper
.get(tool
);
181 toolWrapper
.addProblemDescriptors(Collections
.singletonList(patchedDescriptor
), true);
187 private void inspect(final List
<LocalInspectionTool
> tools
, final InspectionManagerEx iManager
, final boolean isOnTheFly
, final boolean ignoreSuppressed
) {
188 if (tools
.isEmpty()) return;
189 final PsiElement
[] elements
= getElementsIntersectingRange(myFile
, myStartOffset
, myEndOffset
);
191 setProgressLimit(1L * tools
.size() * elements
.length
);
192 final LocalInspectionToolSession session
= new LocalInspectionToolSession(myFile
, myStartOffset
, myEndOffset
);
193 final ProgressIndicator indicator
= ProgressManager
.getInstance().getProgressIndicator();
194 LOG
.assertTrue(indicator
!= null);
196 JobUtil
.invokeConcurrentlyUnderMyProgress(tools
, new Processor
<LocalInspectionTool
>() {
197 public boolean process(final LocalInspectionTool tool
) {
198 final ProgressManager progressManager
= ProgressManager
.getInstance();
199 ProgressManager
.checkCanceled();
200 ProgressIndicator localIndicator
= progressManager
.getProgressIndicator();
202 ProgressIndicator original
= ((ProgressWrapper
)localIndicator
).getOriginalProgressIndicator();
203 LOG
.assertTrue(original
== indicator
, original
);
205 ApplicationManager
.getApplication().assertReadAccessAllowed();
207 ProblemsHolder holder
= new ProblemsHolder(iManager
, myFile
);
208 PsiElementVisitor elementVisitor
= tool
.buildVisitor(holder
, isOnTheFly
);
209 //noinspection ConstantConditions
210 if(elementVisitor
== null) {
211 LOG
.error("Tool " + tool
+ " must not return null from the buildVisitor() method");
213 tool
.inspectionStarted(session
);
214 for (PsiElement element
: elements
) {
215 ProgressManager
.checkCanceled();
216 element
.accept(elementVisitor
);
218 tool
.inspectionFinished(session
);
219 advanceProgress(elements
.length
);
221 if (holder
.hasResults()) {
222 appendDescriptors(holder
.getResults(), tool
, ignoreSuppressed
);
226 }, "Inspection tools");
227 ProgressManager
.checkCanceled();
229 inspectInjectedPsi(elements
, tools
);
231 myInfos
= new ArrayList
<HighlightInfo
>(myDescriptors
.size());
232 addHighlightsFromDescriptors(myInfos
);
233 addHighlightsFromInjectedPsiProblems(myInfos
);
236 void inspectInjectedPsi(final PsiElement
[] elements
, final List
<LocalInspectionTool
> tools
) {
237 myInjectedPsiInspectionResults
= ContainerUtil
.createEmptyCOWList();
238 final Set
<PsiFile
> injected
= new THashSet
<PsiFile
>();
239 for (PsiElement element
: elements
) {
240 InjectedLanguageUtil
.enumerate(element
, myFile
, new PsiLanguageInjectionHost
.InjectedPsiVisitor() {
241 public void visit(@NotNull PsiFile injectedPsi
, @NotNull List
<PsiLanguageInjectionHost
.Shred
> places
) {
242 injected
.add(injectedPsi
);
246 JobUtil
.invokeConcurrentlyUnderMyProgress(injected
, new Processor
<PsiFile
>() {
247 public boolean process(final PsiFile injectedPsi
) {
248 inspectInjectedPsi(injectedPsi
, myInjectedPsiInspectionResults
, tools
);
251 }, "Inspect injected fragments");
254 public Collection
<HighlightInfo
> getHighlights() {
255 ArrayList
<HighlightInfo
> highlights
= new ArrayList
<HighlightInfo
>(myDescriptors
.size());
256 addHighlightsFromDescriptors(highlights
);
257 addHighlightsFromInjectedPsiProblems(highlights
);
261 private static HighlightInfo
highlightInfoFromDescriptor(final ProblemDescriptor problemDescriptor
,
262 final HighlightInfoType highlightInfoType
,
263 final String message
,
264 final String toolTip
) {
265 TextRange textRange
= ((ProblemDescriptorImpl
)problemDescriptor
).getTextRange();
266 PsiElement element
= problemDescriptor
.getPsiElement();
267 boolean isFileLevel
= element
instanceof PsiFile
&& textRange
.equals(element
.getTextRange());
268 HighlightInfo highlightInfo
= new HighlightInfo(null, highlightInfoType
, textRange
.getStartOffset(), textRange
.getEndOffset(), message
,
269 toolTip
, highlightInfoType
.getSeverity(element
), problemDescriptor
.isAfterEndOfLine(), null,
272 return highlightInfo
;
275 private synchronized void appendDescriptors(List
<ProblemDescriptor
> problemDescriptors
, LocalInspectionTool tool
, boolean ignoreSuppressed
) {
276 if (problemDescriptors
== null) return;
277 InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
278 final HighlightSeverity severity
= inspectionProfile
.getErrorLevel(HighlightDisplayKey
.find(tool
.getShortName()), myFile
).getSeverity();
279 for (ProblemDescriptor problemDescriptor
: problemDescriptors
) {
280 ProgressManager
.checkCanceled();
281 if (!(ignoreSuppressed
&& InspectionManagerEx
.inspectionResultSuppressed(problemDescriptor
.getPsiElement(), tool
))) {
282 myDescriptors
.add(problemDescriptor
);
283 HighlightInfoType type
= highlightTypeFromDescriptor(problemDescriptor
, severity
);
291 private HighlightInfoType
highlightTypeFromDescriptor(final ProblemDescriptor problemDescriptor
, final HighlightSeverity severity
) {
292 final ProblemHighlightType highlightType
= problemDescriptor
.getHighlightType();
293 switch (highlightType
) {
294 case GENERIC_ERROR_OR_WARNING
:
295 return mySeverityRegistrar
.getHighlightInfoTypeBySeverity(severity
);
296 case LIKE_DEPRECATED
:
297 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, HighlightInfoType
.DEPRECATED
.getAttributesKey());
298 case LIKE_UNKNOWN_SYMBOL
:
299 if (severity
== HighlightSeverity
.ERROR
) {
300 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, HighlightInfoType
.WRONG_REF
.getAttributesKey());
302 else if (severity
== HighlightSeverity
.WARNING
) {
303 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, CodeInsightColors
.INFO_ATTRIBUTES
);
306 return mySeverityRegistrar
.getHighlightInfoTypeBySeverity(severity
);
308 case LIKE_UNUSED_SYMBOL
:
309 return new HighlightInfoType
.HighlightInfoTypeImpl(severity
, HighlightInfoType
.UNUSED_SYMBOL
.getAttributesKey());
311 return HighlightInfoType
.INFO
;
313 return HighlightInfoType
.WRONG_REF
;
315 return HighlightInfoType
.ERROR
;
317 final TextAttributesKey attributes
= ((ProblemDescriptorImpl
)problemDescriptor
).getEnforcedTextAttributes();
318 if (attributes
!= null) {
319 return new HighlightInfoType
.HighlightInfoTypeImpl(HighlightSeverity
.INFORMATION
, attributes
);
321 return HighlightInfoType
.INFORMATION
;
323 throw new RuntimeException("Cannot map " + highlightType
);
326 protected void applyInformationWithProgress() {
327 UpdateHighlightersUtil
.setHighlightersToEditor(myProject
, myDocument
, myStartOffset
, myEndOffset
, myInfos
, getId());
330 private void addHighlightsFromDescriptors(final List
<HighlightInfo
> toInfos
) {
331 Set
<TextRange
> emptyActionRegistered
= new THashSet
<TextRange
>();
332 for (int i
= 0; i
< myDescriptors
.size(); i
++) {
333 ProblemDescriptor descriptor
= myDescriptors
.get(i
);
334 LocalInspectionTool tool
= myTools
.get(i
);
335 final HighlightInfoType level
= myLevels
.get(i
);
336 HighlightInfo highlightInfo
= createHighlightInfo(descriptor
, tool
, level
, emptyActionRegistered
);
337 if (highlightInfo
!= null) {
338 toInfos
.add(highlightInfo
);
343 private void addHighlightsFromInjectedPsiProblems(final List
<HighlightInfo
> infos
) {
344 Set
<TextRange
> emptyActionRegistered
= new THashSet
<TextRange
>();
345 InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
346 PsiDocumentManager documentManager
= PsiDocumentManager
.getInstance(myProject
);
347 InjectedLanguageManager ilManager
= InjectedLanguageManager
.getInstance(myProject
);
348 for (InjectedPsiInspectionResult result
: myInjectedPsiInspectionResults
) {
349 LocalInspectionTool tool
= result
.tool
;
350 HighlightSeverity severity
= inspectionProfile
.getErrorLevel(HighlightDisplayKey
.find(tool
.getShortName()), myFile
).getSeverity();
352 PsiElement injectedPsi
= result
.injectedPsi
;
353 DocumentWindow documentRange
= (DocumentWindow
)documentManager
.getDocument((PsiFile
)injectedPsi
);
354 if (documentRange
== null) continue;
355 //noinspection ForLoopReplaceableByForEach
356 for (int j
= 0; j
< result
.foundProblems
.size(); j
++) {
357 ProblemDescriptor descriptor
= result
.foundProblems
.get(j
);
358 PsiElement psiElement
= descriptor
.getPsiElement();
359 if (InspectionManagerEx
.inspectionResultSuppressed(psiElement
, tool
)) continue;
360 HighlightInfoType level
= highlightTypeFromDescriptor(descriptor
, severity
);
361 HighlightInfo info
= createHighlightInfo(descriptor
, tool
, level
, emptyActionRegistered
);
362 if (info
== null) continue;
364 // todo we got to separate our "internal" prefixes/suffixes from user-defined ones
365 // todo in the latter case the erors should be highlighted, otherwise not
366 List
<TextRange
> editables
=
367 ilManager
.intersectWithAllEditableFragments((PsiFile
)injectedPsi
, new TextRange(info
.startOffset
, info
.endOffset
));
368 for (TextRange editable
: editables
) {
369 TextRange hostRange
= documentRange
.injectedToHost(editable
);
370 HighlightInfo patched
= HighlightInfo
.createHighlightInfo(info
.type
, psiElement
, hostRange
.getStartOffset(), hostRange
.getEndOffset(), info
.description
, info
.toolTip
);
371 if (patched
!= null) {
372 registerQuickFixes(tool
, descriptor
, patched
, emptyActionRegistered
);
381 private HighlightInfo
createHighlightInfo(final ProblemDescriptor descriptor
, final LocalInspectionTool tool
, final HighlightInfoType level
,
382 final Set
<TextRange
> emptyActionRegistered
) {
383 PsiElement psiElement
= descriptor
.getPsiElement();
384 if (psiElement
== null) return null;
385 @NonNls String message
= renderDescriptionMessage(descriptor
);
387 final HighlightDisplayKey key
= HighlightDisplayKey
.find(tool
.getShortName());
388 final InspectionProfile inspectionProfile
= InspectionProjectProfileManager
.getInstance(myProject
).getInspectionProfile();
389 if (!inspectionProfile
.isToolEnabled(key
, myFile
)) return null;
391 HighlightInfoType type
= new HighlightInfoType
.HighlightInfoTypeImpl(level
.getSeverity(psiElement
), level
.getAttributesKey());
392 final String plainMessage
= message
.startsWith("<html>") ? StringUtil
.unescapeXml(message
.replaceAll("<[^>]*>", "")) : message
;
393 @NonNls final String link
= "<a href=\"#inspection/" + tool
.getShortName() + "\"> " + DaemonBundle
.message("inspection.extended.description") +
394 "</a>" + myShortcutText
;
396 @NonNls String tooltip
= null;
397 if (descriptor
.showTooltip()) {
398 if (message
.startsWith("<html>")) {
399 tooltip
= message
.contains("</body>") ? message
.replace("</body>", link
+ "</body>") : message
.replace("</html>", link
+ "</html>");
402 tooltip
= "<html><body>" + XmlStringUtil
.escapeString(message
) + link
+ "</body></html>";
405 HighlightInfo highlightInfo
= highlightInfoFromDescriptor(descriptor
, type
, plainMessage
, tooltip
);
406 registerQuickFixes(tool
, descriptor
, highlightInfo
, emptyActionRegistered
);
407 return highlightInfo
;
410 private static void registerQuickFixes(final LocalInspectionTool tool
, final ProblemDescriptor descriptor
,
411 final HighlightInfo highlightInfo
, final Set
<TextRange
> emptyActionRegistered
) {
412 final HighlightDisplayKey key
= HighlightDisplayKey
.find(tool
.getShortName());
413 boolean needEmptyAction
= true;
414 final QuickFix
[] fixes
= descriptor
.getFixes();
415 if (fixes
!= null && fixes
.length
> 0) {
416 for (int k
= 0; k
< fixes
.length
; k
++) {
417 if (fixes
[k
] != null) { // prevent null fixes from var args
418 QuickFixAction
.registerQuickFixAction(highlightInfo
, QuickFixWrapper
.wrap(descriptor
, k
), key
);
419 needEmptyAction
= false;
423 HintAction hintAction
= ((ProblemDescriptorImpl
)descriptor
).getHintAction();
424 if (hintAction
!= null) {
425 QuickFixAction
.registerQuickFixAction(highlightInfo
, hintAction
, key
);
426 needEmptyAction
= false;
428 if (((ProblemDescriptorImpl
)descriptor
).getEnforcedTextAttributes() != null) {
429 needEmptyAction
= false;
431 if (needEmptyAction
&& emptyActionRegistered
.add(new TextRange(highlightInfo
.fixStartOffset
, highlightInfo
.fixEndOffset
))) {
432 EmptyIntentionAction emptyIntentionAction
= new EmptyIntentionAction(tool
.getDisplayName());
433 QuickFixAction
.registerQuickFixAction(highlightInfo
, emptyIntentionAction
, key
);
437 private static String
renderDescriptionMessage(ProblemDescriptor descriptor
) {
438 PsiElement psiElement
= descriptor
.getPsiElement();
439 String message
= descriptor
.getDescriptionTemplate();
441 // no message. Should not be the case if inspection correctly implemented.
442 // noinspection ConstantConditions
443 if (message
== null) return "";
445 message
= StringUtil
.replace(message
, "<code>", "'");
446 message
= StringUtil
.replace(message
, "</code>", "'");
447 //message = message.replaceAll("<[^>]*>", "");
448 String ref
= ProblemDescriptionNode
.extractHighlightedText(descriptor
, psiElement
);
449 message
= StringUtil
.replace(message
, "#loc", "");
450 message
= StringUtil
.replace(message
, "#ref", ref
);
452 message
= StringUtil
.unescapeXml(message
).trim();
456 public static PsiElement
[] getElementsIntersectingRange(PsiFile file
, final int startOffset
, final int endOffset
) {
457 final FileViewProvider viewProvider
= file
.getViewProvider();
458 final Set
<PsiElement
> result
= new LinkedHashSet
<PsiElement
>();
459 for (Language language
: viewProvider
.getLanguages()) {
460 final PsiFile psiRoot
= viewProvider
.getPsi(language
);
461 if (HighlightLevelUtil
.shouldInspect(psiRoot
)) {
462 result
.addAll(CollectHighlightsUtil
.getElementsInRange(psiRoot
, startOffset
, endOffset
, true));
465 return result
.toArray(new PsiElement
[result
.size()]);
468 List
<LocalInspectionTool
> getInspectionTools(InspectionProfileWrapper profile
) {
469 return profile
.getHighlightingLocalInspectionTools(myFile
);
472 private static void inspectInjectedPsi(PsiFile injectedPsi
, List
<InjectedPsiInspectionResult
> result
, List
<LocalInspectionTool
> tools
) {
473 InspectionManager inspectionManager
= InspectionManager
.getInstance(injectedPsi
.getProject());
474 final ProblemsHolder problemsHolder
= new ProblemsHolder(inspectionManager
, injectedPsi
);
475 final PsiElement host
= injectedPsi
.getContext();
477 final PsiElement
[] elements
= getElementsIntersectingRange(injectedPsi
, 0, injectedPsi
.getTextLength());
478 if (elements
.length
!= 0) {
479 for (LocalInspectionTool tool
: tools
) {
480 if (host
!= null && InspectionManagerEx
.inspectionResultSuppressed(host
, tool
)) {
483 final PsiElementVisitor visitor
= tool
.buildVisitor(problemsHolder
, true);
484 assert !(visitor
instanceof PsiRecursiveElementVisitor
) : "The visitor returned from LocalInspectionTool.buildVisitor() must not be recursive. "+tool
;
485 for (PsiElement element
: elements
) {
486 element
.accept(visitor
);
488 List
<ProblemDescriptor
> problems
= problemsHolder
.getResults();
489 if (problems
!= null && !problems
.isEmpty()) {
490 InjectedPsiInspectionResult res
= new InjectedPsiInspectionResult(tool
, injectedPsi
, new SmartList
<ProblemDescriptor
>(problems
));
497 public List
<HighlightInfo
> getInfos() {
501 private static class InjectedPsiInspectionResult
{
502 public final LocalInspectionTool tool
;
503 public final PsiElement injectedPsi
;
504 public final List
<ProblemDescriptor
> foundProblems
;
506 private InjectedPsiInspectionResult(final LocalInspectionTool tool
, final PsiElement injectedPsi
, final List
<ProblemDescriptor
> foundProblems
) {
508 this.injectedPsi
= injectedPsi
;
509 this.foundProblems
= foundProblems
;