update copyrights
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / DaemonCodeAnalyzerImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.codeInsight.daemon.impl;
18
19 import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
20 import com.intellij.codeHighlighting.HighlightingPass;
21 import com.intellij.codeHighlighting.Pass;
22 import com.intellij.codeHighlighting.TextEditorHighlightingPass;
23 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
24 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
25 import com.intellij.codeInsight.daemon.LineMarkerInfo;
26 import com.intellij.codeInsight.daemon.ReferenceImporter;
27 import com.intellij.codeInsight.hint.HintManager;
28 import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
29 import com.intellij.concurrency.Job;
30 import com.intellij.lang.annotation.HighlightSeverity;
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.Editor;
35 import com.intellij.openapi.editor.ex.EditorMarkupModel;
36 import com.intellij.openapi.editor.markup.MarkupModel;
37 import com.intellij.openapi.editor.markup.RangeHighlighter;
38 import com.intellij.openapi.extensions.Extensions;
39 import com.intellij.openapi.fileEditor.FileEditor;
40 import com.intellij.openapi.fileEditor.TextEditor;
41 import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
42 import com.intellij.openapi.fileTypes.FileType;
43 import com.intellij.openapi.fileTypes.StdFileTypes;
44 import com.intellij.openapi.progress.ProgressIndicator;
45 import com.intellij.openapi.project.Project;
46 import com.intellij.openapi.util.*;
47 import com.intellij.openapi.vfs.VirtualFile;
48 import com.intellij.openapi.vfs.VirtualFileManager;
49 import com.intellij.packageDependencies.DependencyValidationManager;
50 import com.intellij.psi.PsiCompiledElement;
51 import com.intellij.psi.PsiDocumentManager;
52 import com.intellij.psi.PsiFile;
53 import com.intellij.psi.PsiFileSystemItem;
54 import com.intellij.psi.search.scope.packageSet.NamedScope;
55 import com.intellij.psi.search.scope.packageSet.NamedScopeManager;
56 import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
57 import com.intellij.util.Alarm;
58 import com.intellij.util.SmartList;
59 import com.intellij.util.containers.ContainerUtil;
60 import gnu.trove.THashMap;
61 import gnu.trove.THashSet;
62 import org.jdom.Element;
63 import org.jetbrains.annotations.NonNls;
64 import org.jetbrains.annotations.NotNull;
65 import org.jetbrains.annotations.Nullable;
66 import org.jetbrains.annotations.TestOnly;
67
68 import java.util.*;
69
70 /**
71  * This class also controls the auto-reparse and auto-hints.
72  */
73 public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMExternalizable {
74   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl");
75
76   private static final Key<List<HighlightInfo>> HIGHLIGHTS_IN_EDITOR_DOCUMENT_KEY = Key.create("HIGHLIGHTS_IN_EDITOR_DOCUMENT");
77   private static final Key<List<LineMarkerInfo>> MARKERS_IN_EDITOR_DOCUMENT_KEY = Key.create("MARKERS_IN_EDITOR_DOCUMENT");
78
79   private final Project myProject;
80   private final DaemonCodeAnalyzerSettings mySettings;
81   private final EditorTracker myEditorTracker;
82   private DaemonProgressIndicator myUpdateProgress = new DaemonProgressIndicator();
83   private DaemonProgressIndicator myUpdateVisibleProgress = new DaemonProgressIndicator();
84
85   private final Runnable myUpdateRunnable = createUpdateRunnable();
86
87   private final Alarm myAlarm = new Alarm();
88
89   private boolean myUpdateByTimerEnabled = true;
90   private final Collection<VirtualFile> myDisabledHintsFiles = new THashSet<VirtualFile>();
91   private final Collection<PsiFile> myDisabledHighlightingFiles = new THashSet<PsiFile>();
92   private final FileStatusMap myFileStatusMap;
93
94   private DaemonCodeAnalyzerSettings myLastSettings;
95   private IntentionHintComponent myLastIntentionHint;
96
97   private boolean myDisposed;
98   private boolean myInitialized;
99   @NonNls private static final String DISABLE_HINTS_TAG = "disable_hints";
100
101   @NonNls private static final String FILE_TAG = "file";
102   @NonNls private static final String URL_ATT = "url";
103   private DaemonListeners myDaemonListeners;
104   private StatusBarUpdater myStatusBarUpdater;
105   private final PassExecutorService myPassExecutorService;
106   private static final Key<List<HighlightInfo>> HIGHLIGHTS_TO_REMOVE_KEY = Key.create("HIGHLIGHTS_TO_REMOVE");
107
108   public DaemonCodeAnalyzerImpl(Project project, DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, EditorTracker editorTracker) {
109     myProject = project;
110
111     mySettings = daemonCodeAnalyzerSettings;
112     myEditorTracker = editorTracker;
113     myLastSettings = (DaemonCodeAnalyzerSettings)mySettings.clone();
114
115     myFileStatusMap = new FileStatusMap(myProject);
116     myPassExecutorService = new PassExecutorService(myProject) {
117       protected void afterApplyInformationToEditor(final TextEditorHighlightingPass pass,
118                                                    final FileEditor fileEditor,
119                                                    final ProgressIndicator updateProgress) {
120         if (fileEditor instanceof TextEditor) {
121           log(updateProgress, pass, "Apply ");
122           Editor editor = ((TextEditor)fileEditor).getEditor();
123           repaintErrorStripeRenderer(editor);
124         }
125       }
126
127       protected boolean isDisposed() {
128         return myDisposed || super.isDisposed();
129       }
130     };
131     Disposer.register(project, myPassExecutorService);
132     Disposer.register(project, myFileStatusMap);
133   }
134
135   @NotNull
136   public String getComponentName() {
137     return "DaemonCodeAnalyzer";
138   }
139
140   public void initComponent() {
141   }
142
143   public void disposeComponent() {
144   }
145
146   public void projectOpened() {
147     assert !myInitialized : "Double Initializing";
148     myStatusBarUpdater = new StatusBarUpdater(myProject);
149     Disposer.register(myProject, myStatusBarUpdater);
150
151     myDaemonListeners = new DaemonListeners(myProject, this, myEditorTracker);
152     Disposer.register(myProject, myDaemonListeners);
153     reloadScopes();
154
155     myInitialized = true;
156     myDisposed = false;
157     myFileStatusMap.markAllFilesDirty();
158   }
159
160   public void projectClosed() {
161     assert myInitialized : "Disposing not initialized component";
162     assert !myDisposed : "Double dispose";
163
164     // clear dangling references to PsiFiles/Documents. SCR#10358
165     myFileStatusMap.markAllFilesDirty();
166
167     stopProcess(false);
168
169     myDisposed = true;
170     myLastSettings = null;
171     myInitialized = false;
172   }
173
174   @TestOnly
175   public boolean isInitialized() {
176     return myInitialized;
177   }
178
179   void repaintErrorStripeRenderer(Editor editor) {
180     if (myProject.isDisposed()) return;
181     final Document document = editor.getDocument();
182     final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
183     final EditorMarkupModel markup = (EditorMarkupModel)editor.getMarkupModel();
184     markup.setErrorStripeRenderer(new TrafficLightRenderer(myProject, this, document, psiFile));
185     markup.setErrorPanelPopupHandler(new DaemonEditorPopup(psiFile));
186     markup.setErrorStripTooltipRendererProvider(new DaemonTooltipRendererProvider(myProject));
187     markup.setMinMarkHeight(DaemonCodeAnalyzerSettings.getInstance().ERROR_STRIPE_MARK_MIN_HEIGHT);
188   }
189
190   private final List<Pair<NamedScope, NamedScopesHolder>> myScopes = ContainerUtil.createEmptyCOWList();
191   void reloadScopes() {
192     ApplicationManager.getApplication().assertIsDispatchThread();
193     List<Pair<NamedScope, NamedScopesHolder>> scopeList = new ArrayList<Pair<NamedScope, NamedScopesHolder>>();
194     addScopesToList(scopeList, NamedScopeManager.getInstance(myProject));
195     addScopesToList(scopeList, DependencyValidationManager.getInstance(myProject));
196     myScopes.clear();
197     myScopes.addAll(scopeList);
198   }
199
200   private static void addScopesToList(final List<Pair<NamedScope, NamedScopesHolder>> scopeList, final NamedScopesHolder holder) {
201     NamedScope[] scopes = holder.getScopes();
202     for (NamedScope scope : scopes) {
203       scopeList.add(Pair.create(scope, holder));
204     }
205   }
206
207   @NotNull
208   public List<Pair<NamedScope, NamedScopesHolder>> getScopeBasedHighlightingCachedScopes() {
209     return myScopes;
210   }
211
212   public void settingsChanged() {
213     DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance();
214     if (settings.isCodeHighlightingChanged(myLastSettings)) {
215       restart();
216     }
217     myLastSettings = (DaemonCodeAnalyzerSettings)settings.clone();
218   }
219
220   public void updateVisibleHighlighters(@NotNull Editor editor) {
221     ApplicationManager.getApplication().assertIsDispatchThread();
222     if (ApplicationManager.getApplication().isUnitTestMode()) return;
223
224     final TextEditor textEditor = TextEditorProvider.getInstance().getTextEditor(editor);
225     BackgroundEditorHighlighter highlighter = textEditor.getBackgroundHighlighter();
226     if (highlighter == null) return;
227     final HighlightingPass[] highlightingPasses = highlighter.createPassesForVisibleArea();
228     //setLastIntentionHint(null);
229
230     myPassExecutorService.renewVisiblePasses(textEditor, highlightingPasses, myUpdateVisibleProgress);
231   }
232
233   private void renewUpdateVisibleProgress() {
234     myUpdateVisibleProgress.cancel();
235     myUpdateVisibleProgress = new DaemonProgressIndicator();
236     myUpdateVisibleProgress.start();
237   }
238
239   public void setUpdateByTimerEnabled(boolean value) {
240     myUpdateByTimerEnabled = value;
241     stopProcess(true);
242   }
243
244   public void setImportHintsEnabled(PsiFile file, boolean value) {
245     VirtualFile vFile = file.getVirtualFile();
246     if (value) {
247       myDisabledHintsFiles.remove(vFile);
248       stopProcess(true);
249     }
250     else {
251       myDisabledHintsFiles.add(vFile);
252       HintManager.getInstance().hideAllHints();
253     }
254   }
255
256   public void resetImportHintsEnabledForProject() {
257     myDisabledHintsFiles.clear();
258   }
259
260   public void setHighlightingEnabled(PsiFile file, boolean value) {
261     if (value) {
262       myDisabledHighlightingFiles.remove(file);
263     }
264     else {
265       myDisabledHighlightingFiles.add(file);
266     }
267   }
268
269   public boolean isHighlightingAvailable(PsiFile file) {
270     if (myDisabledHighlightingFiles.contains(file)) return false;
271
272     if (file == null || !file.isPhysical()) return false;
273     if (file instanceof PsiCompiledElement) return false;
274     final FileType fileType = file.getFileType();
275     if (fileType == StdFileTypes.GUI_DESIGNER_FORM){
276       return true;
277     }
278     // To enable T.O.D.O. highlighting
279     return !fileType.isBinary();
280   }
281
282   public boolean isImportHintsEnabled(PsiFile file) {
283     return isAutohintsAvailable(file) && !myDisabledHintsFiles.contains(file.getVirtualFile());
284   }
285
286   public boolean isAutohintsAvailable(PsiFile file) {
287     return isHighlightingAvailable(file) && !(file instanceof PsiCompiledElement);
288   }
289
290   public void restart() {
291     myFileStatusMap.markAllFilesDirty();
292     stopProcess(true);
293   }
294
295   public List<TextEditorHighlightingPass> getPassesToShowProgressFor(PsiFile file) {
296     Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
297     List<TextEditorHighlightingPass> allPasses = myPassExecutorService.getAllSubmittedPasses();
298     List<TextEditorHighlightingPass> result = new ArrayList<TextEditorHighlightingPass>(allPasses.size());
299     for (TextEditorHighlightingPass pass : allPasses) {
300       if (pass.getDocument() == document || pass.getDocument() == null) {
301         result.add(pass);
302       }
303     }
304     return result;
305   }
306
307   public boolean isAllAnalysisFinished(PsiFile file) {
308     if (myDisposed) return false;
309     Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file);
310     return document != null &&
311            document.getModificationStamp() == file.getModificationStamp() &&
312            myFileStatusMap.allDirtyScopesAreNull(document);
313   }
314
315   public boolean isErrorAnalyzingFinished(PsiFile file) {
316     if (myDisposed) return false;
317     Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file);
318     return document != null &&
319            document.getModificationStamp() == file.getModificationStamp() &&
320            myFileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL) == null;
321   }
322
323   public FileStatusMap getFileStatusMap() {
324     return myFileStatusMap;
325   }
326
327   public synchronized ProgressIndicator getUpdateProgress() {
328     return myUpdateProgress;
329   }
330
331   public synchronized void stopProcess(boolean toRestartAlarm) {
332     PassExecutorService.log(myUpdateProgress, null, "Cancel by stopProcess ", toRestartAlarm);
333     renewUpdateProgress(toRestartAlarm);
334     myAlarm.cancelAllRequests();
335     boolean restart = toRestartAlarm && !myDisposed && myInitialized/* && myDaemonListeners.myIsFrameFocused*/;
336     if (restart) {
337       myAlarm.addRequest(myUpdateRunnable, mySettings.AUTOREPARSE_DELAY);
338     }
339   }
340
341   private synchronized void renewUpdateProgress(final boolean start) {
342     myUpdateProgress.cancel();
343     myPassExecutorService.cancelAll();
344     renewUpdateVisibleProgress();
345     if (myUpdateProgress instanceof MockDaemonProgressIndicator) {
346       myUpdateProgress = new MockDaemonProgressIndicator(((MockDaemonProgressIndicator)myUpdateProgress).myStoppedNotify);
347     }
348     else {
349       DaemonProgressIndicator indicator = new DaemonProgressIndicator();
350       myUpdateProgress = indicator;
351       if (start) {
352         indicator.start();
353       }
354     }
355   }
356
357   @Nullable
358   public static List<HighlightInfo> getHighlights(Document document, Project project) {
359     LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
360     MarkupModel markup = document.getMarkupModel(project);
361     return getHighlights(markup);
362   }
363
364   static List<HighlightInfo> getHighlights(MarkupModel markup) {
365     return markup.getUserData(HIGHLIGHTS_IN_EDITOR_DOCUMENT_KEY);
366   }
367
368   @NotNull
369   public static List<HighlightInfo> getHighlights(Document document, HighlightSeverity minSeverity, Project project) {
370     return getHighlights(document, minSeverity, project, Integer.MIN_VALUE, Integer.MAX_VALUE);
371   }
372
373   @NotNull
374   public static List<HighlightInfo> getHighlights(Document document, HighlightSeverity minSeverity, Project project, int startOffset, int endOffset) {
375     LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
376     List<HighlightInfo> highlights = getHighlights(document, project);
377     if (highlights == null) return Collections.emptyList();
378     List<HighlightInfo> array = new ArrayList<HighlightInfo>();
379     final SeverityRegistrar instance = SeverityRegistrar.getInstance(project);
380
381     for (HighlightInfo info : highlights) {
382       if (instance.compare(info.getSeverity(), minSeverity) >= 0 &&
383           info.startOffset >= startOffset &&
384           info.endOffset <= endOffset) {
385         array.add(info);
386       }
387     }
388     return array;
389   }
390
391   @NotNull
392   public static List<HighlightInfo> getHighlightsAround(Document document, Project project, int offset) {
393     LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
394     List<HighlightInfo> highlights = getHighlights(document, project);
395     if (highlights == null) return Collections.emptyList();
396     List<HighlightInfo> array = new ArrayList<HighlightInfo>();
397
398     for (HighlightInfo info : highlights) {
399       if (isOffsetInsideHighlightInfo(offset, info, true)) {
400         array.add(info);
401       }
402     }
403     return array;
404   }
405
406   @Nullable
407   public HighlightInfo findHighlightByOffset(Document document, int offset, boolean includeFixRange) {
408     List<HighlightInfo> highlights = getHighlights(document, myProject);
409     if (highlights == null) return null;
410
411     List<HighlightInfo> foundInfoList = new SmartList<HighlightInfo>();
412     for (HighlightInfo info : highlights) {
413       if (!isOffsetInsideHighlightInfo(offset, info, includeFixRange)) continue;
414
415       if (!foundInfoList.isEmpty()) {
416         HighlightInfo foundInfo = foundInfoList.get(0);
417         int compare = SeverityRegistrar.getInstance(myProject).compare(foundInfo.getSeverity(), info.getSeverity());
418         if (compare < 0) {
419           foundInfoList.clear();
420         }
421         else if (compare > 0) {
422           continue;
423         }
424       }
425       foundInfoList.add(info);
426     }
427
428     if (foundInfoList.isEmpty()) return null;
429     if (foundInfoList.size() == 1) return foundInfoList.get(0);
430     return new HighlightInfoComposite(foundInfoList);
431   }
432
433   private static boolean isOffsetInsideHighlightInfo(int offset, HighlightInfo info, boolean includeFixRange) {
434     if (info.highlighter == null || !info.highlighter.isValid()) return false;
435     int startOffset = info.highlighter.getStartOffset();
436     int endOffset = info.highlighter.getEndOffset();
437     if (startOffset > offset || offset > endOffset) {
438       if (!includeFixRange) return false;
439       if (info.fixMarker == null || !info.fixMarker.isValid()) return false;
440       startOffset = info.fixMarker.getStartOffset();
441       endOffset = info.fixMarker.getEndOffset();
442       if (startOffset > offset || offset > endOffset) return false;
443     }
444     return true;
445   }
446
447   static void setHighlights(MarkupModel markup, Project project, List<HighlightInfo> highlightsToSet, List<HighlightInfo> highlightsToRemove) {
448     ApplicationManager.getApplication().assertIsDispatchThread();
449     stripWarningsCoveredByErrors(project, highlightsToSet, markup);
450     markup.putUserData(HIGHLIGHTS_IN_EDITOR_DOCUMENT_KEY, Collections.unmodifiableList(highlightsToSet));
451
452     markup.putUserData(HIGHLIGHTS_TO_REMOVE_KEY, Collections.unmodifiableList(highlightsToRemove));
453
454     DaemonCodeAnalyzer codeAnalyzer = DaemonCodeAnalyzer.getInstance(project);
455     if (codeAnalyzer instanceof DaemonCodeAnalyzerImpl && ((DaemonCodeAnalyzerImpl)codeAnalyzer).myStatusBarUpdater != null) {
456       ((DaemonCodeAnalyzerImpl)codeAnalyzer).myStatusBarUpdater.updateStatus();
457     }
458   }
459
460   private static void stripWarningsCoveredByErrors(final Project project, List<HighlightInfo> highlights, MarkupModel markup) {
461     final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project);
462     Collection<HighlightInfo> errors = new ArrayList<HighlightInfo>();
463     for (HighlightInfo highlight : highlights) {
464       if (severityRegistrar.compare(highlight.getSeverity(), HighlightSeverity.ERROR) >= 0) {
465         errors.add(highlight);
466       }
467     }
468
469     for (Iterator<HighlightInfo> it = highlights.iterator(); it.hasNext();) {
470       HighlightInfo highlight = it.next();
471       if (severityRegistrar.compare(HighlightSeverity.ERROR, highlight.getSeverity()) > 0 && highlight.getSeverity().myVal > 0) {
472         for (HighlightInfo errorInfo : errors) {
473           if (isCoveredBy(highlight, errorInfo)) {
474             it.remove();
475             RangeHighlighter highlighter = highlight.highlighter;
476             if (highlighter != null) {
477               markup.removeHighlighter(highlighter);
478             }
479             break;
480           }
481         }
482       }
483     }
484   }
485
486   private static boolean isCoveredBy(HighlightInfo info, HighlightInfo coveredBy) {
487     return info.startOffset >= coveredBy.startOffset && info.endOffset <= coveredBy.endOffset;
488   }
489
490   @Nullable
491   public static List<LineMarkerInfo> getLineMarkers(Document document, Project project) {
492     ApplicationManager.getApplication().assertIsDispatchThread();
493     MarkupModel markup = document.getMarkupModel(project);
494     return markup.getUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY);
495   }
496
497   public static void setLineMarkers(@NotNull Document document, List<LineMarkerInfo> lineMarkers, Project project) {
498     ApplicationManager.getApplication().assertIsDispatchThread();
499     MarkupModel markup = document.getMarkupModel(project);
500     markup.putUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY, lineMarkers);
501   }
502
503   public synchronized void setLastIntentionHint(IntentionHintComponent hintComponent) {
504     if (myLastIntentionHint != null && myLastIntentionHint.isVisible()) {
505       myLastIntentionHint.hide();
506     }
507     myLastIntentionHint = hintComponent;
508   }
509
510   public synchronized IntentionHintComponent getLastIntentionHint() {
511     return myLastIntentionHint;
512   }
513
514   public void writeExternal(Element parentNode) throws WriteExternalException {
515     Element disableHintsElement = new Element(DISABLE_HINTS_TAG);
516     parentNode.addContent(disableHintsElement);
517
518     List<String> array = new ArrayList<String>();
519     for (VirtualFile file : myDisabledHintsFiles) {
520       if (file.isValid()) {
521         array.add(file.getUrl());
522       }
523     }
524     Collections.sort(array);
525
526     for (String url : array) {
527       Element fileElement = new Element(FILE_TAG);
528       fileElement.setAttribute(URL_ATT, url);
529       disableHintsElement.addContent(fileElement);
530     }
531   }
532
533   public void readExternal(Element parentNode) throws InvalidDataException {
534     myDisabledHintsFiles.clear();
535
536     Element element = parentNode.getChild(DISABLE_HINTS_TAG);
537     if (element != null) {
538       for (Object o : element.getChildren(FILE_TAG)) {
539         Element e = (Element)o;
540
541         String url = e.getAttributeValue(URL_ATT);
542         if (url != null) {
543           VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url);
544           if (file != null) {
545             myDisabledHintsFiles.add(file);
546           }
547         }
548       }
549     }
550   }
551
552   private Runnable createUpdateRunnable() {
553     return new Runnable() {
554       public void run() {
555         if (!myUpdateByTimerEnabled) return;
556         if (myDisposed || myProject.isDisposed()) return;
557         final Collection<FileEditor> activeEditors = myDaemonListeners.getSelectedEditors();
558         if (activeEditors.isEmpty()) return;
559         Map<FileEditor, HighlightingPass[]> passes = new THashMap<FileEditor, HighlightingPass[]>(activeEditors.size());
560         for (FileEditor fileEditor : activeEditors) {
561           BackgroundEditorHighlighter highlighter = fileEditor.getBackgroundHighlighter();
562           if (highlighter != null) {
563             HighlightingPass[] highlightingPasses = highlighter.createPassesForEditor();
564             passes.put(fileEditor, highlightingPasses);
565           }
566         }
567         // cancel all after calling createPasses() since there are perverts {@link com.intellij.util.xml.ui.DomUIFactoryImpl} who are changing PSI there
568         PassExecutorService.log(myUpdateProgress, null, "Cancel by alarm");
569         renewUpdateProgress(true);
570         myAlarm.cancelAllRequests();
571         DaemonProgressIndicator progress = myUpdateProgress;
572         LOG.assertTrue(progress.isRunning());
573         myPassExecutorService.submitPasses(passes, progress, Job.DEFAULT_PRIORITY);
574       }
575     };
576   }
577
578   public boolean canChangeFileSilently(PsiFileSystemItem file) {
579     return myDaemonListeners.canChangeFileSilently(file);
580   }
581
582   public void autoImportReferenceAtCursor(@NotNull Editor editor, @NotNull PsiFile file) {
583     for(ReferenceImporter importer: Extensions.getExtensions(ReferenceImporter.EP_NAME)) {
584       if (importer.autoImportReferenceAtCursor(editor, file)) break;
585     }
586   }
587
588   @NotNull
589   static List<HighlightInfo> getHighlightsToRemove(MarkupModel markup) {
590     List<HighlightInfo> infos = markup.getUserData(HIGHLIGHTS_TO_REMOVE_KEY);
591     return infos == null ? Collections.<HighlightInfo>emptyList() : infos;
592   }
593
594   @NotNull
595   @TestOnly
596   public static List<HighlightInfo> getFileLeveleHighlights(Project project,PsiFile file ) {
597     return UpdateHighlightersUtil.getFileLeveleHighlights(project, file);
598   }
599 }