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
.analysis
;
19 import com
.intellij
.codeInsight
.daemon
.impl
.*;
20 import com
.intellij
.codeInsight
.highlighting
.HighlightErrorFilter
;
21 import com
.intellij
.lang
.Language
;
22 import com
.intellij
.lang
.LanguageAnnotators
;
23 import com
.intellij
.lang
.annotation
.Annotation
;
24 import com
.intellij
.lang
.annotation
.Annotator
;
25 import com
.intellij
.openapi
.extensions
.ExtensionPointName
;
26 import com
.intellij
.openapi
.extensions
.Extensions
;
27 import com
.intellij
.openapi
.project
.DumbAware
;
28 import com
.intellij
.openapi
.project
.DumbService
;
29 import com
.intellij
.openapi
.project
.Project
;
30 import com
.intellij
.openapi
.util
.TextRange
;
31 import com
.intellij
.openapi
.util
.text
.StringUtil
;
32 import com
.intellij
.psi
.*;
33 import org
.jetbrains
.annotations
.NotNull
;
35 import java
.util
.Collection
;
36 import java
.util
.List
;
41 public class DefaultHighlightVisitor
extends PsiElementVisitor
implements HighlightVisitor
, DumbAware
{
42 private final AnnotationHolderImpl myAnnotationHolder
= new AnnotationHolderImpl();
43 private HighlightInfoHolder myHolder
;
45 public static final ExtensionPointName
<HighlightErrorFilter
> FILTER_EP_NAME
= ExtensionPointName
.create("com.intellij.highlightErrorFilter");
46 private final HighlightErrorFilter
[] myErrorFilters
;
47 private final Project myProject
;
49 public DefaultHighlightVisitor(Project project
) {
51 myErrorFilters
= Extensions
.getExtensions(FILTER_EP_NAME
, project
);
54 public boolean suitableForFile(final PsiFile file
) {
58 public void visit(final PsiElement element
, final HighlightInfoHolder holder
) {
60 assert !myAnnotationHolder
.hasAnnotations() : myAnnotationHolder
;
64 public boolean analyze(final Runnable action
, final boolean updateWholeFile
, final PsiFile file
) {
69 myAnnotationHolder
.clear();
75 public HighlightVisitor
clone() {
76 return new DefaultHighlightVisitor(myProject
);
83 public void visitElement(final PsiElement element
) {
84 runAnnotators(element
);
87 private static final PerThreadMap
<Annotator
,Language
> cachedAnnotators
= new PerThreadMap
<Annotator
, Language
>() {
90 public Collection
<Annotator
> initialValue(@NotNull Language key
) {
91 return LanguageAnnotators
.INSTANCE
.allForLanguage(key
);
95 private void runAnnotators(final PsiElement element
) {
96 List
<Annotator
> annotators
= cachedAnnotators
.get(element
.getLanguage());
97 if (!annotators
.isEmpty()) {
98 final boolean dumb
= DumbService
.getInstance(myProject
).isDumb();
99 //noinspection ForLoopReplaceableByForEach
100 for (int i
= 0; i
< annotators
.size(); i
++) {
101 Annotator annotator
= annotators
.get(i
);
102 if (dumb
&& !(annotator
instanceof DumbAware
)) {
106 annotator
.annotate(element
, myAnnotationHolder
);
108 if (myAnnotationHolder
.hasAnnotations()) {
109 for (Annotation annotation
: myAnnotationHolder
) {
110 myHolder
.add(HighlightInfo
.fromAnnotation(annotation
));
112 myAnnotationHolder
.clear();
117 public void visitErrorElement(final PsiErrorElement element
) {
118 for(HighlightErrorFilter errorFilter
: myErrorFilters
) {
119 if (!errorFilter
.shouldHighlightErrorElement(element
)) return;
122 HighlightInfo info
= createErrorElementInfo(element
);
126 public static HighlightInfo
createErrorElementInfo(final PsiErrorElement element
) {
127 TextRange range
= element
.getTextRange();
128 if (!range
.isEmpty()) {
129 final HighlightInfo highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, range
, element
.getErrorDescription());
130 for(ErrorQuickFixProvider provider
: Extensions
.getExtensions(ErrorQuickFixProvider
.EP_NAME
)) {
131 provider
.registerErrorQuickFix(element
, highlightInfo
);
133 return highlightInfo
;
135 int offset
= range
.getStartOffset();
136 PsiFile containingFile
= element
.getContainingFile();
137 int fileLength
= containingFile
.getTextLength();
138 FileViewProvider viewProvider
= containingFile
.getViewProvider();
139 PsiElement elementAtOffset
= viewProvider
.findElementAt(offset
, viewProvider
.getBaseLanguage());
140 String text
= elementAtOffset
== null ?
null : elementAtOffset
.getText();
142 if (offset
< fileLength
&& text
!= null && !StringUtil
.startsWithChar(text
, '\n') && !StringUtil
.startsWithChar(text
, '\r')) {
143 info
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, offset
, offset
+ 1, element
.getErrorDescription());
149 start
= offset
/* - 1*/;
154 end
= offset
< fileLength ? offset
+ 1 : offset
;
156 info
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, element
, start
, end
, element
.getErrorDescription(),element
.getErrorDescription(), true, null);