leaked CmdMerger in UndoManager in tests
[fedora-idea.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / DaemonCodeAnalyzerImpl.java
bloba2ba213911ff9307b7c550cdee6cb0a5a4dbb93d
1 package com.intellij.codeInsight.daemon.impl;
3 import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
4 import com.intellij.codeHighlighting.HighlightingPass;
5 import com.intellij.codeHighlighting.Pass;
6 import com.intellij.codeHighlighting.TextEditorHighlightingPass;
7 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
8 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
9 import com.intellij.codeInsight.daemon.LineMarkerInfo;
10 import com.intellij.codeInsight.daemon.ReferenceImporter;
11 import com.intellij.codeInsight.hint.HintManager;
12 import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
13 import com.intellij.concurrency.Job;
14 import com.intellij.lang.annotation.HighlightSeverity;
15 import com.intellij.openapi.application.ApplicationManager;
16 import com.intellij.openapi.diagnostic.Logger;
17 import com.intellij.openapi.editor.Document;
18 import com.intellij.openapi.editor.Editor;
19 import com.intellij.openapi.editor.ex.EditorMarkupModel;
20 import com.intellij.openapi.editor.markup.MarkupModel;
21 import com.intellij.openapi.editor.markup.RangeHighlighter;
22 import com.intellij.openapi.extensions.Extensions;
23 import com.intellij.openapi.fileEditor.FileEditor;
24 import com.intellij.openapi.fileEditor.TextEditor;
25 import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
26 import com.intellij.openapi.fileTypes.FileType;
27 import com.intellij.openapi.fileTypes.StdFileTypes;
28 import com.intellij.openapi.progress.ProgressIndicator;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.util.*;
31 import com.intellij.openapi.vfs.VirtualFile;
32 import com.intellij.openapi.vfs.VirtualFileManager;
33 import com.intellij.packageDependencies.DependencyValidationManager;
34 import com.intellij.psi.PsiCompiledElement;
35 import com.intellij.psi.PsiDocumentManager;
36 import com.intellij.psi.PsiFile;
37 import com.intellij.psi.PsiFileSystemItem;
38 import com.intellij.psi.search.scope.packageSet.NamedScope;
39 import com.intellij.psi.search.scope.packageSet.NamedScopeManager;
40 import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
41 import com.intellij.util.Alarm;
42 import com.intellij.util.SmartList;
43 import com.intellij.util.containers.ContainerUtil;
44 import gnu.trove.THashMap;
45 import gnu.trove.THashSet;
46 import org.jdom.Element;
47 import org.jetbrains.annotations.NonNls;
48 import org.jetbrains.annotations.NotNull;
49 import org.jetbrains.annotations.Nullable;
50 import org.jetbrains.annotations.TestOnly;
52 import java.util.*;
54 /**
55 * This class also controls the auto-reparse and auto-hints.
57 public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMExternalizable {
58 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl");
60 private static final Key<List<HighlightInfo>> HIGHLIGHTS_IN_EDITOR_DOCUMENT_KEY = Key.create("HIGHLIGHTS_IN_EDITOR_DOCUMENT");
61 private static final Key<List<LineMarkerInfo>> MARKERS_IN_EDITOR_DOCUMENT_KEY = Key.create("MARKERS_IN_EDITOR_DOCUMENT");
63 private final Project myProject;
64 private final DaemonCodeAnalyzerSettings mySettings;
65 private final EditorTracker myEditorTracker;
66 private DaemonProgressIndicator myUpdateProgress = new DaemonProgressIndicator();
67 private DaemonProgressIndicator myUpdateVisibleProgress = new DaemonProgressIndicator();
69 private final Runnable myUpdateRunnable = createUpdateRunnable();
71 private final Alarm myAlarm = new Alarm();
73 private boolean myUpdateByTimerEnabled = true;
74 private final Collection<VirtualFile> myDisabledHintsFiles = new THashSet<VirtualFile>();
75 private final Collection<PsiFile> myDisabledHighlightingFiles = new THashSet<PsiFile>();
76 private final FileStatusMap myFileStatusMap;
78 private DaemonCodeAnalyzerSettings myLastSettings;
79 private IntentionHintComponent myLastIntentionHint;
81 private boolean myDisposed;
82 private boolean myInitialized;
83 @NonNls private static final String DISABLE_HINTS_TAG = "disable_hints";
85 @NonNls private static final String FILE_TAG = "file";
86 @NonNls private static final String URL_ATT = "url";
87 private DaemonListeners myDaemonListeners;
88 private StatusBarUpdater myStatusBarUpdater;
89 private final PassExecutorService myPassExecutorService;
90 private static final Key<List<HighlightInfo>> HIGHLIGHTS_TO_REMOVE_KEY = Key.create("HIGHLIGHTS_TO_REMOVE");
92 public DaemonCodeAnalyzerImpl(Project project, DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, EditorTracker editorTracker) {
93 myProject = project;
95 mySettings = daemonCodeAnalyzerSettings;
96 myEditorTracker = editorTracker;
97 myLastSettings = (DaemonCodeAnalyzerSettings)mySettings.clone();
99 myFileStatusMap = new FileStatusMap(myProject);
100 myPassExecutorService = new PassExecutorService(myProject) {
101 protected void afterApplyInformationToEditor(final TextEditorHighlightingPass pass,
102 final FileEditor fileEditor,
103 final ProgressIndicator updateProgress) {
104 if (fileEditor instanceof TextEditor) {
105 log(updateProgress, pass, "Apply ");
106 Editor editor = ((TextEditor)fileEditor).getEditor();
107 repaintErrorStripeRenderer(editor);
111 protected boolean isDisposed() {
112 return myDisposed || super.isDisposed();
115 Disposer.register(project, myPassExecutorService);
116 Disposer.register(project, myFileStatusMap);
119 @NotNull
120 public String getComponentName() {
121 return "DaemonCodeAnalyzer";
124 public void initComponent() {
127 public void disposeComponent() {
130 public void projectOpened() {
131 assert !myInitialized : "Double Initializing";
132 myStatusBarUpdater = new StatusBarUpdater(myProject);
133 Disposer.register(myProject, myStatusBarUpdater);
135 myDaemonListeners = new DaemonListeners(myProject, this, myEditorTracker);
136 Disposer.register(myProject, myDaemonListeners);
137 reloadScopes();
139 myInitialized = true;
140 myDisposed = false;
141 myFileStatusMap.markAllFilesDirty();
144 public void projectClosed() {
145 assert myInitialized : "Disposing not initialized component";
146 assert !myDisposed : "Double dispose";
148 // clear dangling references to PsiFiles/Documents. SCR#10358
149 myFileStatusMap.markAllFilesDirty();
151 stopProcess(false);
153 myDisposed = true;
154 myLastSettings = null;
155 myInitialized = false;
158 @TestOnly
159 public boolean isInitialized() {
160 return myInitialized;
163 void repaintErrorStripeRenderer(Editor editor) {
164 if (myProject.isDisposed()) return;
165 final Document document = editor.getDocument();
166 final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
167 final EditorMarkupModel markup = (EditorMarkupModel)editor.getMarkupModel();
168 markup.setErrorStripeRenderer(new TrafficLightRenderer(myProject, this, document, psiFile));
169 markup.setErrorPanelPopupHandler(new DaemonEditorPopup(psiFile));
170 markup.setErrorStripTooltipRendererProvider(new DaemonTooltipRendererProvider(myProject));
171 markup.setMinMarkHeight(DaemonCodeAnalyzerSettings.getInstance().ERROR_STRIPE_MARK_MIN_HEIGHT);
174 private final List<Pair<NamedScope, NamedScopesHolder>> myScopes = ContainerUtil.createEmptyCOWList();
175 void reloadScopes() {
176 ApplicationManager.getApplication().assertIsDispatchThread();
177 List<Pair<NamedScope, NamedScopesHolder>> scopeList = new ArrayList<Pair<NamedScope, NamedScopesHolder>>();
178 addScopesToList(scopeList, NamedScopeManager.getInstance(myProject));
179 addScopesToList(scopeList, DependencyValidationManager.getInstance(myProject));
180 myScopes.clear();
181 myScopes.addAll(scopeList);
184 private static void addScopesToList(final List<Pair<NamedScope, NamedScopesHolder>> scopeList, final NamedScopesHolder holder) {
185 NamedScope[] scopes = holder.getScopes();
186 for (NamedScope scope : scopes) {
187 scopeList.add(Pair.create(scope, holder));
191 @NotNull
192 public List<Pair<NamedScope, NamedScopesHolder>> getScopeBasedHighlightingCachedScopes() {
193 return myScopes;
196 public void settingsChanged() {
197 DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance();
198 if (settings.isCodeHighlightingChanged(myLastSettings)) {
199 restart();
201 myLastSettings = (DaemonCodeAnalyzerSettings)settings.clone();
204 public void updateVisibleHighlighters(@NotNull Editor editor) {
205 ApplicationManager.getApplication().assertIsDispatchThread();
206 if (ApplicationManager.getApplication().isUnitTestMode()) return;
208 final TextEditor textEditor = TextEditorProvider.getInstance().getTextEditor(editor);
209 BackgroundEditorHighlighter highlighter = textEditor.getBackgroundHighlighter();
210 if (highlighter == null) return;
211 final HighlightingPass[] highlightingPasses = highlighter.createPassesForVisibleArea();
212 //setLastIntentionHint(null);
214 myPassExecutorService.renewVisiblePasses(textEditor, highlightingPasses, myUpdateVisibleProgress);
217 private void renewUpdateVisibleProgress() {
218 myUpdateVisibleProgress.cancel();
219 myUpdateVisibleProgress = new DaemonProgressIndicator();
220 myUpdateVisibleProgress.start();
223 public void setUpdateByTimerEnabled(boolean value) {
224 myUpdateByTimerEnabled = value;
225 stopProcess(true);
228 public void setImportHintsEnabled(PsiFile file, boolean value) {
229 VirtualFile vFile = file.getVirtualFile();
230 if (value) {
231 myDisabledHintsFiles.remove(vFile);
232 stopProcess(true);
234 else {
235 myDisabledHintsFiles.add(vFile);
236 HintManager.getInstance().hideAllHints();
240 public void resetImportHintsEnabledForProject() {
241 myDisabledHintsFiles.clear();
244 public void setHighlightingEnabled(PsiFile file, boolean value) {
245 if (value) {
246 myDisabledHighlightingFiles.remove(file);
248 else {
249 myDisabledHighlightingFiles.add(file);
253 public boolean isHighlightingAvailable(PsiFile file) {
254 if (myDisabledHighlightingFiles.contains(file)) return false;
256 if (file == null || !file.isPhysical()) return false;
257 if (file instanceof PsiCompiledElement) return false;
258 final FileType fileType = file.getFileType();
259 if (fileType == StdFileTypes.GUI_DESIGNER_FORM){
260 return true;
262 // To enable T.O.D.O. highlighting
263 return !fileType.isBinary();
266 public boolean isImportHintsEnabled(PsiFile file) {
267 return isAutohintsAvailable(file) && !myDisabledHintsFiles.contains(file.getVirtualFile());
270 public boolean isAutohintsAvailable(PsiFile file) {
271 return isHighlightingAvailable(file) && !(file instanceof PsiCompiledElement);
274 public void restart() {
275 myFileStatusMap.markAllFilesDirty();
276 stopProcess(true);
279 public List<TextEditorHighlightingPass> getPassesToShowProgressFor(PsiFile file) {
280 Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
281 List<TextEditorHighlightingPass> allPasses = myPassExecutorService.getAllSubmittedPasses();
282 List<TextEditorHighlightingPass> result = new ArrayList<TextEditorHighlightingPass>(allPasses.size());
283 for (TextEditorHighlightingPass pass : allPasses) {
284 if (pass.getDocument() == document || pass.getDocument() == null) {
285 result.add(pass);
288 return result;
291 public boolean isAllAnalysisFinished(PsiFile file) {
292 if (myDisposed) return false;
293 Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file);
294 return document != null &&
295 document.getModificationStamp() == file.getModificationStamp() &&
296 myFileStatusMap.allDirtyScopesAreNull(document);
299 public boolean isErrorAnalyzingFinished(PsiFile file) {
300 if (myDisposed) return false;
301 Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file);
302 return document != null &&
303 document.getModificationStamp() == file.getModificationStamp() &&
304 myFileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL) == null;
307 public FileStatusMap getFileStatusMap() {
308 return myFileStatusMap;
311 public synchronized ProgressIndicator getUpdateProgress() {
312 return myUpdateProgress;
315 public synchronized void stopProcess(boolean toRestartAlarm) {
316 PassExecutorService.log(myUpdateProgress, null, "Cancel by stopProcess ", toRestartAlarm);
317 renewUpdateProgress(toRestartAlarm);
318 myAlarm.cancelAllRequests();
319 boolean restart = toRestartAlarm && !myDisposed && myInitialized/* && myDaemonListeners.myIsFrameFocused*/;
320 if (restart) {
321 myAlarm.addRequest(myUpdateRunnable, mySettings.AUTOREPARSE_DELAY);
325 private synchronized void renewUpdateProgress(final boolean start) {
326 myUpdateProgress.cancel();
327 myPassExecutorService.cancelAll();
328 renewUpdateVisibleProgress();
329 if (myUpdateProgress instanceof MockDaemonProgressIndicator) {
330 myUpdateProgress = new MockDaemonProgressIndicator(((MockDaemonProgressIndicator)myUpdateProgress).myStoppedNotify);
332 else {
333 DaemonProgressIndicator indicator = new DaemonProgressIndicator();
334 myUpdateProgress = indicator;
335 if (start) {
336 indicator.start();
341 @Nullable
342 public static List<HighlightInfo> getHighlights(Document document, Project project) {
343 LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
344 MarkupModel markup = document.getMarkupModel(project);
345 return getHighlights(markup);
348 static List<HighlightInfo> getHighlights(MarkupModel markup) {
349 return markup.getUserData(HIGHLIGHTS_IN_EDITOR_DOCUMENT_KEY);
352 @NotNull
353 public static List<HighlightInfo> getHighlights(Document document, HighlightSeverity minSeverity, Project project) {
354 return getHighlights(document, minSeverity, project, Integer.MIN_VALUE, Integer.MAX_VALUE);
357 @NotNull
358 public static List<HighlightInfo> getHighlights(Document document, HighlightSeverity minSeverity, Project project, int startOffset, int endOffset) {
359 LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
360 List<HighlightInfo> highlights = getHighlights(document, project);
361 if (highlights == null) return Collections.emptyList();
362 List<HighlightInfo> array = new ArrayList<HighlightInfo>();
363 final SeverityRegistrar instance = SeverityRegistrar.getInstance(project);
365 for (HighlightInfo info : highlights) {
366 if (instance.compare(info.getSeverity(), minSeverity) >= 0 &&
367 info.startOffset >= startOffset &&
368 info.endOffset <= endOffset) {
369 array.add(info);
372 return array;
375 @NotNull
376 public static List<HighlightInfo> getHighlightsAround(Document document, Project project, int offset) {
377 LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed());
378 List<HighlightInfo> highlights = getHighlights(document, project);
379 if (highlights == null) return Collections.emptyList();
380 List<HighlightInfo> array = new ArrayList<HighlightInfo>();
382 for (HighlightInfo info : highlights) {
383 if (isOffsetInsideHighlightInfo(offset, info, true)) {
384 array.add(info);
387 return array;
390 @Nullable
391 public HighlightInfo findHighlightByOffset(Document document, int offset, boolean includeFixRange) {
392 List<HighlightInfo> highlights = getHighlights(document, myProject);
393 if (highlights == null) return null;
395 List<HighlightInfo> foundInfoList = new SmartList<HighlightInfo>();
396 for (HighlightInfo info : highlights) {
397 if (!isOffsetInsideHighlightInfo(offset, info, includeFixRange)) continue;
399 if (!foundInfoList.isEmpty()) {
400 HighlightInfo foundInfo = foundInfoList.get(0);
401 int compare = SeverityRegistrar.getInstance(myProject).compare(foundInfo.getSeverity(), info.getSeverity());
402 if (compare < 0) {
403 foundInfoList.clear();
405 else if (compare > 0) {
406 continue;
409 foundInfoList.add(info);
412 if (foundInfoList.isEmpty()) return null;
413 if (foundInfoList.size() == 1) return foundInfoList.get(0);
414 return new HighlightInfoComposite(foundInfoList);
417 private static boolean isOffsetInsideHighlightInfo(int offset, HighlightInfo info, boolean includeFixRange) {
418 if (info.highlighter == null || !info.highlighter.isValid()) return false;
419 int startOffset = info.highlighter.getStartOffset();
420 int endOffset = info.highlighter.getEndOffset();
421 if (startOffset > offset || offset > endOffset) {
422 if (!includeFixRange) return false;
423 if (info.fixMarker == null || !info.fixMarker.isValid()) return false;
424 startOffset = info.fixMarker.getStartOffset();
425 endOffset = info.fixMarker.getEndOffset();
426 if (startOffset > offset || offset > endOffset) return false;
428 return true;
431 static void setHighlights(MarkupModel markup, Project project, List<HighlightInfo> highlightsToSet, List<HighlightInfo> highlightsToRemove) {
432 ApplicationManager.getApplication().assertIsDispatchThread();
433 stripWarningsCoveredByErrors(project, highlightsToSet, markup);
434 markup.putUserData(HIGHLIGHTS_IN_EDITOR_DOCUMENT_KEY, Collections.unmodifiableList(highlightsToSet));
436 markup.putUserData(HIGHLIGHTS_TO_REMOVE_KEY, Collections.unmodifiableList(highlightsToRemove));
438 DaemonCodeAnalyzer codeAnalyzer = DaemonCodeAnalyzer.getInstance(project);
439 if (codeAnalyzer instanceof DaemonCodeAnalyzerImpl && ((DaemonCodeAnalyzerImpl)codeAnalyzer).myStatusBarUpdater != null) {
440 ((DaemonCodeAnalyzerImpl)codeAnalyzer).myStatusBarUpdater.updateStatus();
444 private static void stripWarningsCoveredByErrors(final Project project, List<HighlightInfo> highlights, MarkupModel markup) {
445 final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project);
446 Collection<HighlightInfo> errors = new ArrayList<HighlightInfo>();
447 for (HighlightInfo highlight : highlights) {
448 if (severityRegistrar.compare(highlight.getSeverity(), HighlightSeverity.ERROR) >= 0) {
449 errors.add(highlight);
453 for (Iterator<HighlightInfo> it = highlights.iterator(); it.hasNext();) {
454 HighlightInfo highlight = it.next();
455 if (severityRegistrar.compare(HighlightSeverity.ERROR, highlight.getSeverity()) > 0 && highlight.getSeverity().myVal > 0) {
456 for (HighlightInfo errorInfo : errors) {
457 if (isCoveredBy(highlight, errorInfo)) {
458 it.remove();
459 RangeHighlighter highlighter = highlight.highlighter;
460 if (highlighter != null) {
461 markup.removeHighlighter(highlighter);
463 break;
470 private static boolean isCoveredBy(HighlightInfo info, HighlightInfo coveredBy) {
471 return info.startOffset >= coveredBy.startOffset && info.endOffset <= coveredBy.endOffset;
474 @Nullable
475 public static List<LineMarkerInfo> getLineMarkers(Document document, Project project) {
476 ApplicationManager.getApplication().assertIsDispatchThread();
477 MarkupModel markup = document.getMarkupModel(project);
478 return markup.getUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY);
481 public static void setLineMarkers(@NotNull Document document, List<LineMarkerInfo> lineMarkers, Project project) {
482 ApplicationManager.getApplication().assertIsDispatchThread();
483 MarkupModel markup = document.getMarkupModel(project);
484 markup.putUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY, lineMarkers);
487 public synchronized void setLastIntentionHint(IntentionHintComponent hintComponent) {
488 if (myLastIntentionHint != null && myLastIntentionHint.isVisible()) {
489 myLastIntentionHint.hide();
491 myLastIntentionHint = hintComponent;
494 public synchronized IntentionHintComponent getLastIntentionHint() {
495 return myLastIntentionHint;
498 public void writeExternal(Element parentNode) throws WriteExternalException {
499 Element disableHintsElement = new Element(DISABLE_HINTS_TAG);
500 parentNode.addContent(disableHintsElement);
502 List<String> array = new ArrayList<String>();
503 for (VirtualFile file : myDisabledHintsFiles) {
504 if (file.isValid()) {
505 array.add(file.getUrl());
508 Collections.sort(array);
510 for (String url : array) {
511 Element fileElement = new Element(FILE_TAG);
512 fileElement.setAttribute(URL_ATT, url);
513 disableHintsElement.addContent(fileElement);
517 public void readExternal(Element parentNode) throws InvalidDataException {
518 myDisabledHintsFiles.clear();
520 Element element = parentNode.getChild(DISABLE_HINTS_TAG);
521 if (element != null) {
522 for (Object o : element.getChildren(FILE_TAG)) {
523 Element e = (Element)o;
525 String url = e.getAttributeValue(URL_ATT);
526 if (url != null) {
527 VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url);
528 if (file != null) {
529 myDisabledHintsFiles.add(file);
536 private Runnable createUpdateRunnable() {
537 return new Runnable() {
538 public void run() {
539 if (!myUpdateByTimerEnabled) return;
540 if (myDisposed || myProject.isDisposed()) return;
541 final Collection<FileEditor> activeEditors = myDaemonListeners.getSelectedEditors();
542 if (activeEditors.isEmpty()) return;
543 Map<FileEditor, HighlightingPass[]> passes = new THashMap<FileEditor, HighlightingPass[]>(activeEditors.size());
544 for (FileEditor fileEditor : activeEditors) {
545 BackgroundEditorHighlighter highlighter = fileEditor.getBackgroundHighlighter();
546 if (highlighter != null) {
547 HighlightingPass[] highlightingPasses = highlighter.createPassesForEditor();
548 passes.put(fileEditor, highlightingPasses);
551 // cancel all after calling createPasses() since there are perverts {@link com.intellij.util.xml.ui.DomUIFactoryImpl} who are changing PSI there
552 PassExecutorService.log(myUpdateProgress, null, "Cancel by alarm");
553 renewUpdateProgress(true);
554 myAlarm.cancelAllRequests();
555 DaemonProgressIndicator progress = myUpdateProgress;
556 LOG.assertTrue(progress.isRunning());
557 myPassExecutorService.submitPasses(passes, progress, Job.DEFAULT_PRIORITY);
562 public boolean canChangeFileSilently(PsiFileSystemItem file) {
563 return myDaemonListeners.canChangeFileSilently(file);
566 public void autoImportReferenceAtCursor(@NotNull Editor editor, @NotNull PsiFile file) {
567 for(ReferenceImporter importer: Extensions.getExtensions(ReferenceImporter.EP_NAME)) {
568 if (importer.autoImportReferenceAtCursor(editor, file)) break;
572 @NotNull
573 static List<HighlightInfo> getHighlightsToRemove(MarkupModel markup) {
574 List<HighlightInfo> infos = markup.getUserData(HIGHLIGHTS_TO_REMOVE_KEY);
575 return infos == null ? Collections.<HighlightInfo>emptyList() : infos;
578 @NotNull
579 @TestOnly
580 public static List<HighlightInfo> getFileLeveleHighlights(Project project,PsiFile file ) {
581 return UpdateHighlightersUtil.getFileLeveleHighlights(project, file);