LAHT test fixed: added extension listener to KeyedExtensionCollector
[fedora-idea.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / analysis / DefaultHighlightVisitor.java
blob1ab591cee168fd6fb6c106470090b3ff42d609b0
1 /*
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.ExtensionPointListener;
26 import com.intellij.openapi.extensions.ExtensionPointName;
27 import com.intellij.openapi.extensions.Extensions;
28 import com.intellij.openapi.extensions.PluginDescriptor;
29 import com.intellij.openapi.project.DumbAware;
30 import com.intellij.openapi.project.DumbService;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.util.TextRange;
33 import com.intellij.openapi.util.text.StringUtil;
34 import com.intellij.psi.*;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
38 import java.util.Collection;
39 import java.util.List;
41 /**
42 * @author yole
44 public class DefaultHighlightVisitor extends PsiElementVisitor implements HighlightVisitor, DumbAware {
45 private final AnnotationHolderImpl myAnnotationHolder = new AnnotationHolderImpl();
46 private HighlightInfoHolder myHolder;
48 public static final ExtensionPointName<HighlightErrorFilter> FILTER_EP_NAME = ExtensionPointName.create("com.intellij.highlightErrorFilter");
49 private final HighlightErrorFilter[] myErrorFilters;
50 private final Project myProject;
52 public DefaultHighlightVisitor(Project project) {
53 myProject = project;
54 myErrorFilters = Extensions.getExtensions(FILTER_EP_NAME, project);
57 public boolean suitableForFile(final PsiFile file) {
58 return true;
61 public void visit(final PsiElement element, final HighlightInfoHolder holder) {
62 myHolder = holder;
63 assert !myAnnotationHolder.hasAnnotations() : myAnnotationHolder;
64 element.accept(this);
67 public boolean analyze(final Runnable action, final boolean updateWholeFile, final PsiFile file) {
68 try {
69 action.run();
71 finally {
72 myAnnotationHolder.clear();
73 myHolder = null;
75 return true;
78 public HighlightVisitor clone() {
79 return new DefaultHighlightVisitor(myProject);
82 public int order() {
83 return 2;
86 public void visitElement(final PsiElement element) {
87 runAnnotators(element);
90 private static final PerThreadMap<Annotator,Language> cachedAnnotators = new PerThreadMap<Annotator, Language>() {
91 @NotNull
92 @Override
93 public Collection<Annotator> initialValue(@NotNull Language key) {
94 return LanguageAnnotators.INSTANCE.allForLanguage(key);
98 static {
99 LanguageAnnotators.INSTANCE.addListener(new ExtensionPointListener<Annotator>() {
100 public void extensionAdded(Annotator extension, @Nullable PluginDescriptor pluginDescriptor) {
101 cachedAnnotators.clear();
104 public void extensionRemoved(Annotator extension, @Nullable PluginDescriptor pluginDescriptor) {
105 cachedAnnotators.clear();
109 //final ExtensionPoint<LanguageExtensionPoint<Annotator>> point = Extensions.getRootArea().getExtensionPoint(LanguageAnnotators.EP_NAME);
110 //point.addExtensionPointListener(new ExtensionPointAndAreaListener<LanguageExtensionPoint<Annotator>>() {
111 // public void areaReplaced(ExtensionsArea area) {
112 // cachedAnnotators.clear();
113 // }
115 // public void extensionAdded(LanguageExtensionPoint<Annotator> extension, @Nullable PluginDescriptor pluginDescriptor) {
116 // cachedAnnotators.clear();
117 // }
119 // public void extensionRemoved(LanguageExtensionPoint<Annotator> extension, @Nullable PluginDescriptor pluginDescriptor) {
120 // cachedAnnotators.clear();
121 // }
122 //});
125 private void runAnnotators(final PsiElement element) {
126 List<Annotator> annotators = cachedAnnotators.get(element.getLanguage());
127 if (!annotators.isEmpty()) {
128 final boolean dumb = DumbService.getInstance(myProject).isDumb();
129 //noinspection ForLoopReplaceableByForEach
130 for (int i = 0; i < annotators.size(); i++) {
131 Annotator annotator = annotators.get(i);
132 if (dumb && !(annotator instanceof DumbAware)) {
133 continue;
136 annotator.annotate(element, myAnnotationHolder);
138 if (myAnnotationHolder.hasAnnotations()) {
139 for (Annotation annotation : myAnnotationHolder) {
140 myHolder.add(HighlightInfo.fromAnnotation(annotation));
142 myAnnotationHolder.clear();
147 public void visitErrorElement(final PsiErrorElement element) {
148 for(HighlightErrorFilter errorFilter: myErrorFilters) {
149 if (!errorFilter.shouldHighlightErrorElement(element)) return;
152 HighlightInfo info = createErrorElementInfo(element);
153 myHolder.add(info);
156 public static HighlightInfo createErrorElementInfo(final PsiErrorElement element) {
157 TextRange range = element.getTextRange();
158 if (!range.isEmpty()) {
159 final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, range, element.getErrorDescription());
160 for(ErrorQuickFixProvider provider: Extensions.getExtensions(ErrorQuickFixProvider.EP_NAME)) {
161 provider.registerErrorQuickFix(element, highlightInfo);
163 return highlightInfo;
165 int offset = range.getStartOffset();
166 PsiFile containingFile = element.getContainingFile();
167 int fileLength = containingFile.getTextLength();
168 FileViewProvider viewProvider = containingFile.getViewProvider();
169 PsiElement elementAtOffset = viewProvider.findElementAt(offset, viewProvider.getBaseLanguage());
170 String text = elementAtOffset == null ? null : elementAtOffset.getText();
171 HighlightInfo info;
172 if (offset < fileLength && text != null && !StringUtil.startsWithChar(text, '\n') && !StringUtil.startsWithChar(text, '\r')) {
173 info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, offset, offset + 1, element.getErrorDescription());
175 else {
176 int start;
177 int end;
178 if (offset > 0) {
179 start = offset/* - 1*/;
180 end = offset;
182 else {
183 start = offset;
184 end = offset < fileLength ? offset + 1 : offset;
186 info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, element, start, end, element.getErrorDescription(),element.getErrorDescription(), true, null);
188 return info;