IDEADEV-41249
[fedora-idea.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / GeneralHighlightingPass.java
blobf51eb7287c5b1b85bea9024feb5dddc74bf96142
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;
19 import com.intellij.codeHighlighting.Pass;
20 import com.intellij.codeHighlighting.TextEditorHighlightingPass;
21 import com.intellij.codeInsight.daemon.DaemonBundle;
22 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
23 import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder;
24 import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil;
25 import com.intellij.codeInsight.problems.ProblemImpl;
26 import com.intellij.concurrency.JobUtil;
27 import com.intellij.injected.editor.DocumentWindow;
28 import com.intellij.lang.Language;
29 import com.intellij.lang.annotation.HighlightSeverity;
30 import com.intellij.lang.injection.InjectedLanguageManager;
31 import com.intellij.openapi.application.ApplicationManager;
32 import com.intellij.openapi.diagnostic.Logger;
33 import com.intellij.openapi.editor.Document;
34 import com.intellij.openapi.editor.HighlighterColors;
35 import com.intellij.openapi.editor.RangeMarker;
36 import com.intellij.openapi.editor.colors.EditorColors;
37 import com.intellij.openapi.editor.colors.EditorColorsManager;
38 import com.intellij.openapi.editor.colors.EditorColorsScheme;
39 import com.intellij.openapi.editor.colors.TextAttributesKey;
40 import com.intellij.openapi.editor.markup.TextAttributes;
41 import com.intellij.openapi.extensions.Extensions;
42 import com.intellij.openapi.fileTypes.SyntaxHighlighter;
43 import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
44 import com.intellij.openapi.progress.ProcessCanceledException;
45 import com.intellij.openapi.progress.ProgressIndicator;
46 import com.intellij.openapi.progress.ProgressManager;
47 import com.intellij.openapi.project.DumbAware;
48 import com.intellij.openapi.project.DumbService;
49 import com.intellij.openapi.project.Project;
50 import com.intellij.openapi.util.*;
51 import com.intellij.openapi.vfs.VirtualFile;
52 import com.intellij.problems.Problem;
53 import com.intellij.problems.WolfTheProblemSolver;
54 import com.intellij.psi.*;
55 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
56 import com.intellij.psi.search.PsiSearchHelper;
57 import com.intellij.psi.search.TodoItem;
58 import com.intellij.psi.tree.IElementType;
59 import com.intellij.util.Processor;
60 import com.intellij.util.SmartList;
61 import gnu.trove.THashSet;
62 import org.jetbrains.annotations.NotNull;
64 import javax.swing.*;
65 import java.awt.*;
66 import java.util.*;
67 import java.util.List;
68 import java.util.concurrent.atomic.AtomicInteger;
70 public class GeneralHighlightingPass extends ProgressableTextEditorHighlightingPass implements DumbAware {
71 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass");
72 static final Icon IN_PROGRESS_ICON = IconLoader.getIcon("/general/errorsInProgress.png");
73 static final String PRESENTABLE_NAME = DaemonBundle.message("pass.syntax");
74 private static final Key<Boolean> HAS_ERROR_ELEMENT = Key.create("HAS_ERROR_ELEMENT");
76 private final int myStartOffset;
77 private final int myEndOffset;
78 private final boolean myUpdateAll;
80 private volatile Collection<HighlightInfo> myHighlights = Collections.emptyList();
81 private final Map<TextRange,Collection<HighlightInfo>> myInjectedPsiHighlights = new HashMap<TextRange, Collection<HighlightInfo>>();
83 protected volatile boolean myHasErrorElement;
84 private volatile boolean myErrorFound;
85 private static final Comparator<HighlightVisitor> VISITOR_ORDER_COMPARATOR = new Comparator<HighlightVisitor>() {
86 public int compare(final HighlightVisitor o1, final HighlightVisitor o2) {
87 return o1.order() - o2.order();
90 private volatile UserDataHolder myProgress;
92 public GeneralHighlightingPass(@NotNull Project project,
93 @NotNull PsiFile file,
94 @NotNull Document document,
95 int startOffset,
96 int endOffset,
97 boolean updateAll) {
98 super(project, document, IN_PROGRESS_ICON, PRESENTABLE_NAME, file, true);
99 myStartOffset = startOffset;
100 myEndOffset = endOffset;
101 myUpdateAll = updateAll;
103 LOG.assertTrue(file.isValid());
104 setId(Pass.UPDATE_ALL);
105 myHasErrorElement = !isWholeFileHighlighting() && Boolean.TRUE.equals(myFile.getUserData(HAS_ERROR_ELEMENT));
106 FileStatusMap fileStatusMap = ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject)).getFileStatusMap();
107 myErrorFound = !isWholeFileHighlighting() && fileStatusMap.wasErrorFound(myDocument);
110 private static final Key<AtomicInteger> HIGHLIGHT_VISITOR_INSTANCE_COUNT = new Key<AtomicInteger>("HIGHLIGHT_VISITOR_INSTANCE_COUNT");
111 @NotNull
112 private HighlightVisitor[] createHighlightVisitors() {
113 int oldCount = incVisitorUsageCount(1);
114 HighlightVisitor[] highlightVisitors = Extensions.getExtensions(HighlightVisitor.EP_HIGHLIGHT_VISITOR, myProject);
115 if (oldCount != 0) {
116 HighlightVisitor[] clones = new HighlightVisitor[highlightVisitors.length];
117 for (int i = 0; i < highlightVisitors.length; i++) {
118 HighlightVisitor highlightVisitor = highlightVisitors[i];
119 clones[i] = highlightVisitor.clone();
121 highlightVisitors = clones;
123 return highlightVisitors;
126 // returns old value
127 private int incVisitorUsageCount(int delta) {
128 AtomicInteger count = myProject.getUserData(HIGHLIGHT_VISITOR_INSTANCE_COUNT);
129 if (count == null) {
130 count = ((UserDataHolderEx)myProject).putUserDataIfAbsent(HIGHLIGHT_VISITOR_INSTANCE_COUNT, new AtomicInteger(0));
132 int old = count.getAndAdd(delta);
133 assert old + delta >= 0 : old +";" + delta;
134 return old;
137 protected void collectInformationWithProgress(final ProgressIndicator progress) {
138 myProgress = (UserDataHolder)progress;
139 final Collection<HighlightInfo> result = new THashSet<HighlightInfo>(100);
140 DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(myProject);
141 FileStatusMap fileStatusMap = ((DaemonCodeAnalyzerImpl)daemonCodeAnalyzer).getFileStatusMap();
142 HighlightVisitor[] highlightVisitors = createHighlightVisitors();
143 HighlightVisitor[] filtered = filterVisitors(highlightVisitors, myFile);
144 try {
145 final FileViewProvider viewProvider = myFile.getViewProvider();
146 final Set<Language> relevantLanguages = viewProvider.getLanguages();
147 List<PsiElement> elements = null;
148 for (Language language : relevantLanguages) {
149 PsiElement psiRoot = viewProvider.getPsi(language);
150 if (!HighlightLevelUtil.shouldHighlight(psiRoot)) continue;
151 List<PsiElement> underRoot = CollectHighlightsUtil.getElementsInRange(psiRoot, myStartOffset, myEndOffset);
152 if (elements == null) {
153 elements = underRoot;
155 else {
156 elements.addAll(underRoot);
158 if (underRoot.isEmpty()) {
159 elements.add(psiRoot);
162 if (elements != null) {
163 result.addAll(collectHighlights(elements, progress, filtered));
164 addInjectedPsiHighlights(elements);
167 if (!isDumbMode()) {
168 result.addAll(highlightTodos(myFile, myDocument.getCharsSequence(), myStartOffset, myEndOffset));
171 if (myUpdateAll) {
172 fileStatusMap.setErrorFoundFlag(myDocument, myErrorFound);
175 finally {
176 incVisitorUsageCount(-1);
178 myHighlights = result;
181 private void addInjectedPsiHighlights(@NotNull final List<PsiElement> elements) {
182 List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile);
183 Collection<PsiElement> hosts = new THashSet<PsiElement>(elements.size() + injected.size());
185 // rehighlight all injected PSI regardless the range,
186 // since change in one place can lead to invalidation of injected PSI in (completely) other place.
187 for (DocumentWindow documentRange : injected) {
188 if (!documentRange.isValid()) continue;
189 PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange);
190 if (file == null) continue;
191 PsiElement context = file.getContext();
192 if (context != null
193 && context.isValid()
194 && !file.getProject().isDisposed()
195 && (myUpdateAll || new ProperTextRange(myStartOffset, myEndOffset).intersects(context.getTextRange()))) {
196 hosts.add(context);
199 hosts.addAll(elements);
201 final Collection<PsiFile> injectedFiles = new THashSet<PsiFile>();
202 EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
203 final TextAttributes injectedAttributes = scheme.getAttributes(EditorColors.INJECTED_LANGUAGE_FRAGMENT);
205 for (PsiElement element : hosts) {
206 InjectedLanguageUtil.enumerate(element, myFile, new PsiLanguageInjectionHost.InjectedPsiVisitor() {
207 public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
208 if (injectedFiles.add(injectedPsi)) { // for concatenations there can be many injection hosts with only one injected PSI
209 for (PsiLanguageInjectionHost.Shred place : places) {
210 TextRange textRange = place.getRangeInsideHost().shiftRight(place.host.getTextRange().getStartOffset());
211 if (textRange.isEmpty()) continue;
212 String desc = injectedPsi.getText();
213 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, textRange, null, desc, injectedAttributes);
214 addHighlightInfo(textRange, info);
218 }, false);
220 if (injectedFiles.isEmpty()) return;
221 final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(myProject);
223 JobUtil.invokeConcurrentlyUnderMyProgress(injectedFiles, new Processor<PsiFile>() {
224 public boolean process(final PsiFile injectedPsi) {
225 DocumentWindow documentWindow = (DocumentWindow)PsiDocumentManager.getInstance(myProject).getCachedDocument(injectedPsi);
226 HighlightInfoHolder holder = createInfoHolder(injectedPsi);
227 runHighlightVisitosForInjected(injectedPsi, holder);
228 for (int i=0; i<holder.size();i++) {
229 HighlightInfo info = holder.get(i);
230 final int startOffset = documentWindow.injectedToHost(info.startOffset);
231 final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset);
232 addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, fixedTextRange);
234 holder.clear();
235 highlightInjectedSyntax(injectedPsi, holder);
236 for (int i=0; i<holder.size();i++) {
237 HighlightInfo info = holder.get(i);
238 final int startOffset = info.startOffset;
239 final TextRange fixedTextRange = getFixedTextRange(documentWindow, startOffset);
240 if (fixedTextRange == null) {
241 addHighlightInfo(new TextRange(info.startOffset, info.endOffset), info);
243 else {
244 HighlightInfo patched =
245 new HighlightInfo(info.forcedTextAttributes, info.type, fixedTextRange.getStartOffset(), fixedTextRange.getEndOffset(),
246 info.description, info.toolTip, info.type.getSeverity(null), info.isAfterEndOfLine, null, false);
247 addHighlightInfo(fixedTextRange, patched);
251 if (!isDumbMode()) {
252 Collection<HighlightInfo> todos = highlightTodos(injectedPsi, injectedPsi.getText(), 0, injectedPsi.getTextLength());
253 for (HighlightInfo info : todos) {
254 addPatchedInfos(info, injectedPsi, documentWindow, injectedLanguageManager, null);
257 return true;
259 }, "Highlight injected language fragments");
262 private static TextRange getFixedTextRange(@NotNull DocumentWindow documentWindow, int startOffset) {
263 final TextRange fixedTextRange;
264 TextRange textRange = documentWindow.getHostRange(startOffset);
265 if (textRange == null) {
266 // todo[cdr] check this fix. prefix/suffix code annotation case
267 textRange = findNearestTextRange(documentWindow, startOffset);
268 final boolean isBefore = startOffset < textRange.getStartOffset();
269 fixedTextRange = new ProperTextRange(isBefore ? textRange.getStartOffset() - 1 : textRange.getEndOffset(),
270 isBefore ? textRange.getStartOffset() : textRange.getEndOffset() + 1);
272 else {
273 fixedTextRange = null;
275 return fixedTextRange;
278 private void addPatchedInfos(HighlightInfo info, PsiFile injectedPsi, DocumentWindow documentWindow, InjectedLanguageManager injectedLanguageManager,
279 TextRange fixedTextRange) {
280 ProperTextRange textRange = new ProperTextRange(info.startOffset, info.endOffset);
281 List<TextRange> editables = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, textRange);
282 for (TextRange editable : editables) {
283 TextRange hostRange = fixedTextRange == null ? documentWindow.injectedToHost(editable) : fixedTextRange;
285 HighlightInfo patched =
286 new HighlightInfo(info.forcedTextAttributes, info.type, hostRange.getStartOffset(), hostRange.getEndOffset(),
287 info.description, info.toolTip, info.type.getSeverity(null), info.isAfterEndOfLine, null, false);
289 if (info.quickFixActionRanges != null) {
290 for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) {
291 TextRange quickfixTextRange = pair.getSecond();
292 List<TextRange> editableQF = injectedLanguageManager.intersectWithAllEditableFragments(injectedPsi, quickfixTextRange);
293 for (TextRange editableRange : editableQF) {
294 HighlightInfo.IntentionActionDescriptor descriptor = pair.getFirst();
295 if (patched.quickFixActionRanges == null) patched.quickFixActionRanges = new ArrayList<Pair<HighlightInfo.IntentionActionDescriptor, TextRange>>();
296 TextRange hostEditableRange = documentWindow.injectedToHost(editableRange);
297 patched.quickFixActionRanges.add(Pair.create(descriptor, hostEditableRange));
301 addHighlightInfo(hostRange, patched);
305 private void addHighlightInfo(@NotNull TextRange textRange, @NotNull HighlightInfo highlightInfo) {
306 synchronized (myInjectedPsiHighlights) {
307 Collection<HighlightInfo> infos = myInjectedPsiHighlights.get(textRange);
308 if (infos == null) {
309 infos = new SmartList<HighlightInfo>();
310 myInjectedPsiHighlights.put(textRange, infos);
312 infos.add(highlightInfo);
316 // finds the first nearest text range
317 private static TextRange findNearestTextRange(final DocumentWindow documentWindow, final int startOffset) {
318 TextRange textRange = null;
319 for (RangeMarker marker : documentWindow.getHostRanges()) {
320 TextRange curRange = InjectedLanguageUtil.toTextRange(marker);
321 if (curRange.getStartOffset() > startOffset && textRange != null) break;
322 textRange = curRange;
324 assert textRange != null;
325 return textRange;
328 private void runHighlightVisitosForInjected(final PsiFile injectedPsi, final HighlightInfoHolder holder) {
329 HighlightVisitor[] visitors = createHighlightVisitors();
330 try {
331 HighlightVisitor[] filtered = filterVisitors(visitors, injectedPsi);
332 final List<PsiElement> elements = CollectHighlightsUtil.getElementsInRange(injectedPsi, 0, injectedPsi.getTextLength());
333 for (final HighlightVisitor hvisitor : filtered) {
334 hvisitor.analyze(new Runnable() {
335 public void run() {
336 for (PsiElement element : elements) {
337 ProgressManager.checkCanceled();
338 hvisitor.visit(element, holder);
341 }, true, injectedPsi);
344 finally {
345 incVisitorUsageCount(-1);
349 private static void highlightInjectedSyntax(final PsiFile injectedPsi, HighlightInfoHolder holder) {
350 List<Trinity<IElementType, PsiLanguageInjectionHost, TextRange>> tokens = InjectedLanguageUtil.getHighlightTokens(injectedPsi);
351 if (tokens == null) return;
353 final Language injectedLanguage = injectedPsi.getLanguage();
354 SyntaxHighlighter syntaxHighlighter =
355 SyntaxHighlighterFactory.getSyntaxHighlighter(injectedLanguage, injectedPsi.getProject(), injectedPsi.getVirtualFile());
356 EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme();
357 final TextAttributes defaultAttrs = globalScheme.getAttributes(HighlighterColors.TEXT);
359 for (Trinity<IElementType, PsiLanguageInjectionHost, TextRange> token : tokens) {
360 IElementType tokenType = token.getFirst();
361 PsiLanguageInjectionHost injectionHost = token.getSecond();
362 TextRange textRange = token.getThird();
363 TextAttributesKey[] keys = syntaxHighlighter.getTokenHighlights(tokenType);
364 if (textRange.getLength() == 0) continue;
366 TextRange annRange = textRange.shiftRight(injectionHost.getTextRange().getStartOffset());
367 // force attribute colors to override host' ones
368 TextAttributes attributes = null;
369 for(TextAttributesKey key:keys) {
370 TextAttributes attrs2 = globalScheme.getAttributes(key);
371 if (attrs2 != null) {
372 attributes = attributes != null ? TextAttributes.merge(attributes, attrs2):attrs2;
375 TextAttributes forcedAttributes;
376 if (attributes == null || attributes.isEmpty() || attributes.equals(defaultAttrs)) {
377 forcedAttributes = TextAttributes.ERASE_MARKER;
379 else {
380 Color back = attributes.getBackgroundColor() == null ? globalScheme.getDefaultBackground() : attributes.getBackgroundColor();
381 Color fore = attributes.getForegroundColor() == null ? globalScheme.getDefaultForeground() : attributes.getForegroundColor();
382 forcedAttributes = new TextAttributes(fore, back, attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType());
385 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT, annRange, null,null,forcedAttributes);
386 holder.add(info);
390 private boolean isWholeFileHighlighting() {
391 return myUpdateAll && myStartOffset == 0 && myEndOffset == myFile.getTextLength();
394 private static final Key<List<GeneralHighlightingPass>> UPDATE_ALL_FINISHED = Key.create("UPDATE_ALL_FINISHED");
395 protected void applyInformationWithProgress() {
396 myFile.putUserData(HAS_ERROR_ELEMENT, myHasErrorElement);
398 // highlights from both passes should be in the same layer
399 TextRange range = new TextRange(myStartOffset, myEndOffset);
400 Collection<HighlightInfo> collection = myInjectedPsiHighlights.get(range);
401 if (collection == null) {
402 collection = new ArrayList<HighlightInfo>(myHighlights.size());
404 collection.addAll(myHighlights);
405 myInjectedPsiHighlights.put(range, collection);
406 myHighlights = Collections.emptyList();
408 List<GeneralHighlightingPass> updateAllFinished = myProgress.getUserData(UPDATE_ALL_FINISHED);
409 if (updateAllFinished == null || !updateAllFinished.contains(this)) {
410 // prevent situation when visible pass finished after updateAll pass and tries to wipe out its results
411 UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, myInjectedPsiHighlights, Pass.UPDATE_ALL);
413 if (myUpdateAll) {
414 if (updateAllFinished == null) {
415 updateAllFinished = new ArrayList<GeneralHighlightingPass>();
416 myProgress.putUserData(UPDATE_ALL_FINISHED, updateAllFinished);
418 updateAllFinished.add(this);
422 if (myUpdateAll) {
423 reportErrorsToWolf();
427 @NotNull
428 public Collection<HighlightInfo> getHighlights() {
429 ArrayList<HighlightInfo> list = new ArrayList<HighlightInfo>(myHighlights);
430 for (Collection<HighlightInfo> infos : myInjectedPsiHighlights.values()) {
431 list.addAll(infos);
433 return list;
436 private Collection<HighlightInfo> collectHighlights(@NotNull final List<PsiElement> elements, @NotNull final ProgressIndicator progress,
437 final HighlightVisitor[] visitors) {
438 final Set<PsiElement> skipParentsSet = new THashSet<PsiElement>();
439 final Set<HighlightInfo> gotHighlights = new THashSet<HighlightInfo>();
441 final boolean forceHighlightParents = forceHighlightParents();
443 final HighlightInfoHolder holder = createInfoHolder(myFile);
444 setProgressLimit((long)elements.size() * visitors.length);
446 final int chunkSize = Math.max(1, elements.size() / 100); // one percent precision is enough
447 for (final HighlightVisitor visitor : visitors) {
448 Runnable action = new Runnable() {
449 public void run() {
450 int nextLimit = chunkSize;
451 for (int i = 0; i < elements.size(); i++) {
452 PsiElement element = elements.get(i);
453 ProgressManager.checkCanceled();
455 if (element != myFile && !skipParentsSet.isEmpty() && element.getFirstChild() != null && skipParentsSet.contains(element)) {
456 skipParentsSet.add(element.getParent());
457 continue;
460 if (element instanceof PsiErrorElement) {
461 myHasErrorElement = true;
463 holder.clear();
465 visitor.visit(element, holder);
466 if (i == nextLimit) {
467 advanceProgress(chunkSize);
468 nextLimit = i + chunkSize;
471 //noinspection ForLoopReplaceableByForEach
472 for (int j = 0; j < holder.size(); j++) {
473 HighlightInfo info = holder.get(j);
474 assert info != null;
475 // have to filter out already obtained highlights
476 if (!gotHighlights.add(info)) continue;
477 boolean isError = info.getSeverity() == HighlightSeverity.ERROR;
478 if (isError) {
479 if (!forceHighlightParents) {
480 skipParentsSet.add(element.getParent());
482 myErrorFound = true;
486 advanceProgress(elements.size() - (nextLimit-chunkSize));
489 if (!visitor.analyze(action, myUpdateAll, myFile)) {
490 cancelAndRestartDaemonLater(progress, myProject, this);
494 return gotHighlights;
497 private static HighlightVisitor[] filterVisitors(HighlightVisitor[] highlightVisitors, final PsiFile file) {
498 final List<HighlightVisitor> visitors = new ArrayList<HighlightVisitor>(highlightVisitors.length);
499 List<HighlightVisitor> list = Arrays.asList(highlightVisitors);
500 for (HighlightVisitor visitor : DumbService.getInstance(file.getProject()).filterByDumbAwareness(list)) {
501 if (visitor.suitableForFile(file)) visitors.add(visitor);
503 LOG.assertTrue(!visitors.isEmpty(), list);
505 HighlightVisitor[] visitorArray = visitors.toArray(new HighlightVisitor[visitors.size()]);
506 Arrays.sort(visitorArray, VISITOR_ORDER_COMPARATOR);
507 return visitorArray;
510 static Void cancelAndRestartDaemonLater(ProgressIndicator progress, final Project project, TextEditorHighlightingPass pass) {
511 PassExecutorService.log(progress, pass, "Cancel and restart");
512 progress.cancel();
513 ApplicationManager.getApplication().invokeLater(new Runnable() {
514 public void run() {
515 try {
516 Thread.sleep(new Random().nextInt(100));
518 catch (InterruptedException e) {
519 LOG.error(e);
521 DaemonCodeAnalyzer.getInstance(project).restart();
523 }, project.getDisposed());
524 throw new ProcessCanceledException();
527 private boolean forceHighlightParents() {
528 boolean forceHighlightParents = false;
529 for(HighlightRangeExtension extension: Extensions.getExtensions(HighlightRangeExtension.EP_NAME)) {
530 if (extension.isForceHighlightParents(myFile)) {
531 forceHighlightParents = true;
532 break;
535 return forceHighlightParents;
538 protected HighlightInfoHolder createInfoHolder(final PsiFile file) {
539 final HighlightInfoFilter[] filters = ApplicationManager.getApplication().getExtensions(HighlightInfoFilter.EXTENSION_POINT_NAME);
540 return new HighlightInfoHolder(file, filters);
543 private static Collection<HighlightInfo> highlightTodos(PsiFile file, CharSequence text, int startOffset, int endOffset) {
544 PsiManager psiManager = file.getManager();
545 PsiSearchHelper helper = psiManager.getSearchHelper();
546 TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset);
547 if (todoItems.length == 0) return Collections.emptyList();
549 List<HighlightInfo> list = new ArrayList<HighlightInfo>(todoItems.length);
550 for (TodoItem todoItem : todoItems) {
551 TextRange range = todoItem.getTextRange();
552 String description = text.subSequence(range.getStartOffset(), range.getEndOffset()).toString();
553 TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes();
554 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.TODO, range, description, description, attributes);
555 assert info != null;
556 list.add(info);
558 return list;
561 private void reportErrorsToWolf() {
562 if (!myFile.getViewProvider().isPhysical()) return; // e.g. errors in evaluate expression
563 Project project = myFile.getProject();
564 if (!PsiManager.getInstance(project).isInProject(myFile)) return; // do not report problems in libraries
565 VirtualFile file = myFile.getVirtualFile();
566 if (file == null) return;
568 List<Problem> problems = convertToProblems(getHighlights(), file, myHasErrorElement);
569 WolfTheProblemSolver wolf = WolfTheProblemSolver.getInstance(project);
571 List<HighlightInfo> errors = DaemonCodeAnalyzerImpl.getHighlights(getDocument(), HighlightSeverity.ERROR, project);
572 if (errors.isEmpty() || isWholeFileHighlighting()) {
573 wolf.reportProblems(file, problems);
575 else {
576 wolf.weHaveGotProblems(file, problems);
580 public double getProgress() {
581 // do not show progress of visible highlighters update
582 return myUpdateAll ? super.getProgress() : -1;
585 private static List<Problem> convertToProblems(final Collection<HighlightInfo> infos, final VirtualFile file,
586 final boolean hasErrorElement) {
587 List<Problem> problems = new SmartList<Problem>();
588 for (HighlightInfo info : infos) {
589 if (info.getSeverity() == HighlightSeverity.ERROR) {
590 Problem problem = new ProblemImpl(file, info, hasErrorElement);
591 problems.add(problem);
594 return problems;
597 @Override
598 public String toString() {
599 return super.toString() + " updateAll="+myUpdateAll+" range=("+myStartOffset+","+myEndOffset+")";