cancel reparsing if psi is reloaded anyway (e.g. FilePropertyPusher reloads psi)...
[idea/community.git] / platform / core-impl / src / com / intellij / psi / impl / file / impl / FileManagerImpl.java
1 /*
2  * Copyright 2000-2016 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.psi.impl.file.impl;
18
19 import com.intellij.injected.editor.DocumentWindow;
20 import com.intellij.injected.editor.VirtualFileWindow;
21 import com.intellij.lang.Language;
22 import com.intellij.lang.LanguageUtil;
23 import com.intellij.openapi.application.ApplicationManager;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.editor.Document;
26 import com.intellij.openapi.fileEditor.FileDocumentManager;
27 import com.intellij.openapi.fileTypes.FileType;
28 import com.intellij.openapi.project.DumbService;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.roots.FileIndexFacade;
31 import com.intellij.openapi.util.Disposer;
32 import com.intellij.openapi.util.Key;
33 import com.intellij.openapi.util.LowMemoryWatcher;
34 import com.intellij.openapi.util.registry.Registry;
35 import com.intellij.openapi.vfs.VfsUtilCore;
36 import com.intellij.openapi.vfs.VirtualFile;
37 import com.intellij.openapi.vfs.VirtualFileVisitor;
38 import com.intellij.psi.*;
39 import com.intellij.psi.impl.*;
40 import com.intellij.psi.impl.file.PsiDirectoryFactory;
41 import com.intellij.psi.impl.source.PsiFileImpl;
42 import com.intellij.testFramework.LightVirtualFile;
43 import com.intellij.util.ConcurrencyUtil;
44 import com.intellij.util.containers.ContainerUtil;
45 import com.intellij.util.messages.MessageBusConnection;
46 import gnu.trove.THashMap;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
49 import org.jetbrains.annotations.TestOnly;
50
51 import java.util.*;
52 import java.util.concurrent.ConcurrentMap;
53
54 public class FileManagerImpl implements FileManager {
55   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.file.impl.FileManagerImpl");
56   private final Key<FileViewProvider> myPsiHardRefKey = Key.create("HARD_REFERENCE_TO_PSI"); //non-static!
57
58   private final PsiManagerImpl myManager;
59   private final FileIndexFacade myFileIndex;
60
61   private final ConcurrentMap<VirtualFile, PsiDirectory> myVFileToPsiDirMap = ContainerUtil.createConcurrentSoftValueMap();
62   private final ConcurrentMap<VirtualFile, FileViewProvider> myVFileToViewProviderMap = ContainerUtil.createConcurrentWeakValueMap();
63
64   private boolean myInitialized = false;
65   private boolean myDisposed = false;
66
67   private final FileDocumentManager myFileDocumentManager;
68   private final MessageBusConnection myConnection;
69
70   public FileManagerImpl(PsiManagerImpl manager, FileDocumentManager fileDocumentManager, FileIndexFacade fileIndex) {
71     myManager = manager;
72     myFileIndex = fileIndex;
73     myConnection = manager.getProject().getMessageBus().connect();
74
75     myFileDocumentManager = fileDocumentManager;
76
77     Disposer.register(manager.getProject(), this);
78     LowMemoryWatcher.register(new Runnable() {
79       @Override
80       public void run() {
81         processQueue();
82       }
83     }, this);
84   }
85
86   private static final VirtualFile NULL = new LightVirtualFile();
87
88   public void processQueue() {
89     // just to call processQueue()
90     myVFileToViewProviderMap.remove(NULL);
91   }
92
93   @TestOnly
94   @NotNull
95   public ConcurrentMap<VirtualFile, FileViewProvider> getVFileToViewProviderMap() {
96     return myVFileToViewProviderMap;
97   }
98
99   private void updateAllViewProviders() {
100     handleFileTypesChange(new FileTypesChanged() {
101       @Override
102       protected void updateMaps() {
103         for (final FileViewProvider provider : myVFileToViewProviderMap.values()) {
104           if (!provider.getVirtualFile().isValid()) {
105             continue;
106           }
107
108           clearPsiCaches(provider);
109         }
110         removeInvalidFilesAndDirs(false);
111         checkLanguageChange();
112       }
113     });
114   }
115
116   public static void clearPsiCaches(FileViewProvider provider) {
117     if (provider instanceof SingleRootFileViewProvider) {
118       for (PsiFile root : ((SingleRootFileViewProvider)provider).getCachedPsiFiles()) {
119         if (root instanceof PsiFileImpl) {
120           ((PsiFileImpl)root).clearCaches();
121         }
122       }
123     } else {
124       for (Language language : provider.getLanguages()) {
125         final PsiFile psi = provider.getPsi(language);
126         if (psi instanceof PsiFileImpl) {
127           ((PsiFileImpl)psi).clearCaches();
128         }
129       }
130     }
131   }
132
133   private void checkLanguageChange() {
134     Map<VirtualFile, FileViewProvider> fileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
135     Map<VirtualFile, FileViewProvider> originalFileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
136     myVFileToViewProviderMap.clear();
137     for (Iterator<VirtualFile> iterator = fileToPsiFileMap.keySet().iterator(); iterator.hasNext();) {
138       VirtualFile vFile = iterator.next();
139       Language language = LanguageUtil.getLanguageForPsi(myManager.getProject(), vFile);
140       if (language != null && language != fileToPsiFileMap.get(vFile).getBaseLanguage()) {
141         iterator.remove();
142       }
143     }
144     myVFileToViewProviderMap.putAll(fileToPsiFileMap);
145     markInvalidations(originalFileToPsiFileMap);
146   }
147
148   public void forceReload(@NotNull VirtualFile vFile) {
149     LanguageSubstitutors.cancelReparsing(vFile);
150     if (findCachedViewProvider(vFile) == null) {
151       return;
152     }
153     setViewProvider(vFile, null);
154
155     VirtualFile dir = vFile.getParent();
156     PsiDirectory parentDir = dir == null ? null : getCachedDirectory(dir);
157     PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
158     if (parentDir != null) {
159       event.setParent(parentDir);
160       myManager.childrenChanged(event);
161     }
162     else {
163       firePropertyChangedForUnloadedPsi(event, vFile);
164     }
165   }
166
167   void firePropertyChangedForUnloadedPsi(@NotNull PsiTreeChangeEventImpl event, @NotNull VirtualFile vFile) {
168     event.setPropertyName(PsiTreeChangeEvent.PROP_UNLOADED_PSI);
169     event.setOldValue(vFile);
170     event.setNewValue(vFile);
171
172     myManager.beforePropertyChange(event);
173     myManager.propertyChanged(event);
174   }
175
176   @Override
177   public void dispose() {
178     if (myInitialized) {
179       myConnection.disconnect();
180     }
181     ApplicationManager.getApplication().assertWriteAccessAllowed();
182     clearViewProviders();
183
184     myDisposed = true;
185   }
186
187   private void clearViewProviders() {
188     DebugUtil.startPsiModification("clearViewProviders");
189     try {
190       for (final FileViewProvider provider : myVFileToViewProviderMap.values()) {
191         markInvalidated(provider);
192       }
193       myVFileToViewProviderMap.clear();
194     }
195     finally {
196       DebugUtil.finishPsiModification();
197     }
198   }
199
200   @Override
201   @TestOnly
202   public void cleanupForNextTest() {
203     clearViewProviders();
204     myVFileToPsiDirMap.clear();
205     ((PsiModificationTrackerImpl)myManager.getModificationTracker()).incCounter();
206   }
207
208   @Override
209   @NotNull
210   public FileViewProvider findViewProvider(@NotNull final VirtualFile file) {
211     assert !file.isDirectory();
212     FileViewProvider viewProvider = findCachedViewProvider(file);
213     if (viewProvider != null) return viewProvider;
214     viewProvider = ConcurrencyUtil.cacheOrGet(myVFileToViewProviderMap, file, createFileViewProvider(file, true));
215     return viewProvider;
216   }
217
218   @Override
219   public FileViewProvider findCachedViewProvider(@NotNull final VirtualFile file) {
220     FileViewProvider viewProvider = getFromInjected(file);
221     if (viewProvider == null) viewProvider = myVFileToViewProviderMap.get(file);
222     if (viewProvider == null) viewProvider = file.getUserData(myPsiHardRefKey);
223     return viewProvider;
224   }
225
226   @Nullable
227   private FileViewProvider getFromInjected(@NotNull VirtualFile file) {
228     if (file instanceof VirtualFileWindow) {
229       DocumentWindow document = ((VirtualFileWindow)file).getDocumentWindow();
230       PsiFile psiFile = PsiDocumentManager.getInstance(myManager.getProject()).getCachedPsiFile(document);
231       if (psiFile == null) return null;
232       return psiFile.getViewProvider();
233     }
234     return null;
235   }
236
237   @Override
238   public void setViewProvider(@NotNull final VirtualFile virtualFile, @Nullable final FileViewProvider fileViewProvider) {
239     FileViewProvider prev = findCachedViewProvider(virtualFile);
240     if (prev == fileViewProvider) return;
241     if (prev != null) {
242       DebugUtil.startPsiModification(null);
243       try {
244         markInvalidated(prev);
245         DebugUtil.onInvalidated(prev);
246       }
247       finally {
248         DebugUtil.finishPsiModification();
249       }
250     }
251
252     if (!(virtualFile instanceof VirtualFileWindow)) {
253       if (fileViewProvider == null) {
254         myVFileToViewProviderMap.remove(virtualFile);
255       }
256       else {
257         if (virtualFile instanceof LightVirtualFile) {
258           virtualFile.putUserData(myPsiHardRefKey, fileViewProvider);
259         } else {
260           myVFileToViewProviderMap.put(virtualFile, fileViewProvider);
261         }
262       }
263     }
264   }
265
266   @Override
267   @NotNull
268   public FileViewProvider createFileViewProvider(@NotNull final VirtualFile file, boolean eventSystemEnabled) {
269     FileType fileType = file.getFileType();
270     Language language = LanguageUtil.getLanguageForPsi(myManager.getProject(), file);
271     FileViewProviderFactory factory = language == null
272                                       ? FileTypeFileViewProviders.INSTANCE.forFileType(fileType)
273                                       : LanguageFileViewProviders.INSTANCE.forLanguage(language);
274     FileViewProvider viewProvider = factory == null ? null : factory.createFileViewProvider(file, language, myManager, eventSystemEnabled);
275
276     return viewProvider == null ? new SingleRootFileViewProvider(myManager, file, eventSystemEnabled, fileType) : viewProvider;
277   }
278
279   public void markInitialized() {
280     LOG.assertTrue(!myInitialized);
281     myDisposed = false;
282     myInitialized = true;
283
284     myConnection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
285       @Override
286       public void enteredDumbMode() {
287         updateAllViewProviders();
288       }
289
290       @Override
291       public void exitDumbMode() {
292         updateAllViewProviders();
293       }
294     });
295   }
296
297   public boolean isInitialized() {
298     return myInitialized;
299   }
300
301   void processFileTypesChanged() {
302     handleFileTypesChange(new FileTypesChanged() {
303       @Override
304       protected void updateMaps() {
305         removeInvalidFilesAndDirs(true);
306       }
307     });
308   }
309
310   private abstract class FileTypesChanged implements Runnable {
311     protected abstract void updateMaps();
312
313     @Override
314     public void run() {
315       PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
316       event.setPropertyName(PsiTreeChangeEvent.PROP_FILE_TYPES);
317       myManager.beforePropertyChange(event);
318
319       updateMaps();
320
321       myManager.propertyChanged(event);
322     }
323   }
324
325   private boolean myProcessingFileTypesChange = false;
326   private void handleFileTypesChange(@NotNull FileTypesChanged runnable) {
327     if (myProcessingFileTypesChange) return;
328     myProcessingFileTypesChange = true;
329     try {
330       ApplicationManager.getApplication().runWriteAction(runnable);
331     }
332     finally {
333       myProcessingFileTypesChange = false;
334     }
335   }
336
337   void dispatchPendingEvents() {
338     if (!myInitialized) {
339       LOG.error("Project is not yet initialized: "+myManager.getProject());
340     }
341     if (myDisposed) {
342       LOG.error("Project is already disposed: "+myManager.getProject());
343     }
344
345     myConnection.deliverImmediately();
346   }
347
348   @TestOnly
349   public void checkConsistency() {
350     HashMap<VirtualFile, FileViewProvider> fileToViewProvider = new HashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
351     myVFileToViewProviderMap.clear();
352     for (VirtualFile vFile : fileToViewProvider.keySet()) {
353       final FileViewProvider fileViewProvider = fileToViewProvider.get(vFile);
354
355       LOG.assertTrue(vFile.isValid());
356       PsiFile psiFile1 = findFile(vFile);
357       if (psiFile1 != null && fileViewProvider != null && fileViewProvider.isPhysical()) { // might get collected
358         PsiFile psi = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage());
359         assert psi != null : fileViewProvider +"; "+fileViewProvider.getBaseLanguage()+"; "+psiFile1;
360         assert psiFile1.getClass().equals(psi.getClass()) : psiFile1 +"; "+psi + "; "+psiFile1.getClass() +"; "+psi.getClass();
361       }
362     }
363
364     HashMap<VirtualFile, PsiDirectory> fileToPsiDirMap = new HashMap<VirtualFile, PsiDirectory>(myVFileToPsiDirMap);
365     myVFileToPsiDirMap.clear();
366
367     for (VirtualFile vFile : fileToPsiDirMap.keySet()) {
368       LOG.assertTrue(vFile.isValid());
369       PsiDirectory psiDir1 = findDirectory(vFile);
370       LOG.assertTrue(psiDir1 != null);
371
372       VirtualFile parent = vFile.getParent();
373       if (parent != null) {
374         LOG.assertTrue(myVFileToPsiDirMap.containsKey(parent));
375       }
376     }
377   }
378
379   @Override
380   @Nullable
381   public PsiFile findFile(@NotNull VirtualFile vFile) {
382     if (vFile.isDirectory()) return null;
383     final Project project = myManager.getProject();
384     if (project.isDefault()) return null;
385
386     ApplicationManager.getApplication().assertReadAccessAllowed();
387     if (!vFile.isValid()) {
388       LOG.error("Invalid file: " + vFile);
389       return null;
390     }
391
392     dispatchPendingEvents();
393     final FileViewProvider viewProvider = findViewProvider(vFile);
394     return viewProvider.getPsi(viewProvider.getBaseLanguage());
395   }
396
397   @Override
398   @Nullable
399   public PsiFile getCachedPsiFile(@NotNull VirtualFile vFile) {
400     ApplicationManager.getApplication().assertReadAccessAllowed();
401     LOG.assertTrue(vFile.isValid(), "Invalid file");
402     if (myDisposed) {
403       LOG.error("Project is already disposed: " + myManager.getProject());
404     }
405     if (!myInitialized) return null;
406
407     dispatchPendingEvents();
408
409     return getCachedPsiFileInner(vFile);
410   }
411
412   @Override
413   @Nullable
414   public PsiDirectory findDirectory(@NotNull VirtualFile vFile) {
415     LOG.assertTrue(myInitialized, "Access to psi files should be performed only after startup activity");
416     if (myDisposed) {
417       LOG.error("Access to psi files should not be performed after project disposal: "+myManager.getProject());
418     }
419
420
421     ApplicationManager.getApplication().assertReadAccessAllowed();
422     if (!vFile.isValid()) {
423       LOG.error("File is not valid:" + vFile);
424       return null;
425     }
426
427     if (!vFile.isDirectory()) return null;
428     dispatchPendingEvents();
429
430     return findDirectoryImpl(vFile);
431   }
432
433   @Nullable
434   private PsiDirectory findDirectoryImpl(@NotNull VirtualFile vFile) {
435     PsiDirectory psiDir = myVFileToPsiDirMap.get(vFile);
436     if (psiDir != null) return psiDir;
437
438     if (Registry.is("ide.hide.excluded.files")) {
439       if (myFileIndex.isExcludedFile(vFile)) return null;
440     }
441     else {
442       if (myFileIndex.isUnderIgnored(vFile)) return null;
443     }
444
445     VirtualFile parent = vFile.getParent();
446     if (parent != null) { //?
447       findDirectoryImpl(parent);// need to cache parent directory - used for firing events
448     }
449
450     psiDir = PsiDirectoryFactory.getInstance(myManager.getProject()).createDirectory(vFile);
451     return ConcurrencyUtil.cacheOrGet(myVFileToPsiDirMap, vFile, psiDir);
452   }
453
454   public PsiDirectory getCachedDirectory(@NotNull VirtualFile vFile) {
455     return myVFileToPsiDirMap.get(vFile);
456   }
457
458   void removeFilesAndDirsRecursively(@NotNull VirtualFile vFile) {
459     DebugUtil.startPsiModification("removeFilesAndDirsRecursively");
460     try {
461       VfsUtilCore.visitChildrenRecursively(vFile, new VirtualFileVisitor() {
462         @Override
463         public boolean visitFile(@NotNull VirtualFile file) {
464           if (file.isDirectory()) {
465             myVFileToPsiDirMap.remove(file);
466           }
467           else {
468             FileViewProvider viewProvider = myVFileToViewProviderMap.remove(file);
469             if (viewProvider != null) {
470               markInvalidated(viewProvider);
471             }
472           }
473           return true;
474         }
475       });
476     }
477     finally {
478       DebugUtil.finishPsiModification();
479     }
480   }
481
482   private void markInvalidated(@NotNull FileViewProvider viewProvider) {
483     if (viewProvider instanceof SingleRootFileViewProvider) {
484       ((SingleRootFileViewProvider)viewProvider).markInvalidated();
485     }
486     VirtualFile virtualFile = viewProvider.getVirtualFile();
487     Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
488     if (document != null) {
489       ((PsiDocumentManagerBase)PsiDocumentManager.getInstance(myManager.getProject())).associatePsi(document, null);
490     }
491     virtualFile.putUserData(myPsiHardRefKey, null);
492   }
493
494   @Nullable
495   PsiFile getCachedPsiFileInner(@NotNull VirtualFile file) {
496     FileViewProvider fileViewProvider = myVFileToViewProviderMap.get(file);
497     if (fileViewProvider == null) fileViewProvider = file.getUserData(myPsiHardRefKey);
498     return fileViewProvider instanceof SingleRootFileViewProvider
499            ? ((SingleRootFileViewProvider)fileViewProvider).getCachedPsi(fileViewProvider.getBaseLanguage()) : null;
500   }
501
502   @NotNull
503   @Override
504   public List<PsiFile> getAllCachedFiles() {
505     List<PsiFile> files = new ArrayList<PsiFile>();
506     for (FileViewProvider provider : myVFileToViewProviderMap.values()) {
507       if (provider instanceof SingleRootFileViewProvider) {
508         ContainerUtil.addIfNotNull(files, ((SingleRootFileViewProvider)provider).getCachedPsi(provider.getBaseLanguage()));
509       }
510     }
511     return files;
512   }
513
514   void removeInvalidFilesAndDirs(boolean useFind) {
515     Map<VirtualFile, PsiDirectory> fileToPsiDirMap = new THashMap<VirtualFile, PsiDirectory>(myVFileToPsiDirMap);
516     if (useFind) {
517       myVFileToPsiDirMap.clear();
518     }
519     for (Iterator<VirtualFile> iterator = fileToPsiDirMap.keySet().iterator(); iterator.hasNext();) {
520       VirtualFile vFile = iterator.next();
521       if (!vFile.isValid()) {
522         iterator.remove();
523       }
524       else {
525         PsiDirectory psiDir = findDirectory(vFile);
526         if (psiDir == null) {
527           iterator.remove();
528         }
529       }
530     }
531     myVFileToPsiDirMap.clear();
532     myVFileToPsiDirMap.putAll(fileToPsiDirMap);
533
534     // note: important to update directories map first - findFile uses findDirectory!
535     Map<VirtualFile, FileViewProvider> fileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
536     Map<VirtualFile, FileViewProvider> originalFileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
537     if (useFind) {
538       myVFileToViewProviderMap.clear();
539     }
540     for (Iterator<VirtualFile> iterator = fileToPsiFileMap.keySet().iterator(); iterator.hasNext();) {
541       VirtualFile vFile = iterator.next();
542
543       if (!vFile.isValid()) {
544         iterator.remove();
545         continue;
546       }
547
548       if (useFind) {
549         FileViewProvider view = fileToPsiFileMap.get(vFile);
550         if (view == null) { // soft ref. collected
551           iterator.remove();
552           continue;
553         }
554         PsiFile psiFile1 = findFile(vFile);
555         if (psiFile1 == null) {
556           iterator.remove();
557           continue;
558         }
559
560         if (!areViewProvidersEquivalent(view, psiFile1.getViewProvider())) {
561           iterator.remove();
562         }
563         else {
564           clearPsiCaches(view);
565         }
566       }
567     }
568     myVFileToViewProviderMap.clear();
569     myVFileToViewProviderMap.putAll(fileToPsiFileMap);
570
571     markInvalidations(originalFileToPsiFileMap);
572   }
573
574   static boolean areViewProvidersEquivalent(@NotNull FileViewProvider view1, @NotNull FileViewProvider view2) {
575     if (view1.getClass() != view2.getClass() || view1.getFileType() != view2.getFileType()) return false;
576
577     Language baseLanguage = view1.getBaseLanguage();
578     if (baseLanguage != view2.getBaseLanguage()) return false;
579
580     if (!view1.getLanguages().equals(view2.getLanguages())) return false;
581     PsiFile psi1 = view1.getPsi(baseLanguage);
582     PsiFile psi2 = view2.getPsi(baseLanguage);
583     if (psi1 == null) return psi2 == null;
584     if (psi1.getClass() != psi2.getClass()) return false;
585
586     return true;
587   }
588
589   private void markInvalidations(Map<VirtualFile, FileViewProvider> originalFileToPsiFileMap) {
590     DebugUtil.startPsiModification(null);
591     try {
592       for (Map.Entry<VirtualFile, FileViewProvider> entry : originalFileToPsiFileMap.entrySet()) {
593         FileViewProvider viewProvider = entry.getValue();
594         if (myVFileToViewProviderMap.get(entry.getKey()) != viewProvider) {
595           markInvalidated(viewProvider);
596         }
597       }
598     }
599     finally {
600       DebugUtil.finishPsiModification();
601     }
602   }
603
604   @Override
605   public void reloadFromDisk(@NotNull PsiFile file) {
606     reloadFromDisk(file, false);
607   }
608
609   void reloadFromDisk(@NotNull PsiFile file, boolean ignoreDocument) {
610     ApplicationManager.getApplication().assertWriteAccessAllowed();
611     VirtualFile vFile = file.getVirtualFile();
612     assert vFile != null;
613
614     if (file instanceof PsiBinaryFile) return;
615     FileDocumentManager fileDocumentManager = myFileDocumentManager;
616     Document document = fileDocumentManager.getCachedDocument(vFile);
617     if (document != null && !ignoreDocument){
618       fileDocumentManager.reloadFromDisk(document);
619     }
620     else {
621       FileViewProvider latestProvider = createFileViewProvider(vFile, false);
622       if (latestProvider.getPsi(latestProvider.getBaseLanguage()) instanceof PsiBinaryFile) {
623         forceReload(vFile);
624         return;
625       }
626
627       FileViewProvider viewProvider = file.getViewProvider();
628       if (viewProvider instanceof SingleRootFileViewProvider) {
629         ((SingleRootFileViewProvider)viewProvider).onContentReload();
630       } else {
631         LOG.error("Invalid view provider: " + viewProvider + " of " + viewProvider.getClass());
632       }
633     }
634   }
635 }