public void testExternalFileModificationWhileProjectClosed() throws Exception {
    VirtualFile root = ProjectRootManager.getInstance(myProject).getContentRoots()[0];

    PsiClass objectClass =
        myJavaFacade.findClass(
            CommonClassNames.JAVA_LANG_OBJECT, GlobalSearchScope.allScope(getProject()));
    assertNotNull(objectClass);
    checkUsages(objectClass, new String[] {});
    FileBasedIndex.getInstance()
        .getContainingFiles(
            TodoIndex.NAME,
            new TodoIndexEntry("todo", true),
            GlobalSearchScope.allScope(getProject()));

    final String projectLocation = myProject.getPresentableUrl();
    assert projectLocation != null : myProject;
    PlatformTestUtil.saveProject(myProject);
    final VirtualFile content = ModuleRootManager.getInstance(getModule()).getContentRoots()[0];
    Project project = myProject;
    ProjectUtil.closeAndDispose(project);
    InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project);

    assertTrue("Project was not disposed", myProject.isDisposed());
    myModule = null;

    final File file = new File(root.getPath(), "1.java");
    assertTrue(file.exists());

    FileUtil.writeToFile(file, "class A{ Object o;}".getBytes(CharsetToolkit.UTF8_CHARSET));
    root.refresh(false, true);

    LocalFileSystem.getInstance().refresh(false);

    myProject = ProjectManager.getInstance().loadAndOpenProject(projectLocation);
    InjectedLanguageManagerImpl.pushInjectors(getProject());

    setUpModule();
    setUpJdk();
    ProjectManagerEx.getInstanceEx().openTestProject(myProject);
    UIUtil.dispatchAllInvocationEvents(); // startup activities

    runStartupActivities();
    PsiTestUtil.addSourceContentToRoots(getModule(), content);

    assertNotNull(myProject);
    myPsiManager = (PsiManagerImpl) PsiManager.getInstance(myProject);
    myJavaFacade = JavaPsiFacadeEx.getInstanceEx(myProject);

    objectClass =
        myJavaFacade.findClass(
            CommonClassNames.JAVA_LANG_OBJECT, GlobalSearchScope.allScope(getProject()));
    assertNotNull(objectClass);
    checkUsages(objectClass, new String[] {"1.java"});
  }
 @TestOnly
 public static void pushInjectors(@NotNull Project project) {
   InjectedLanguageManagerImpl cachedManager =
       (InjectedLanguageManagerImpl) project.getUserData(INSTANCE_CACHE);
   if (cachedManager == null) return;
   try {
     assert cachedManager.myInjectorsClone.isEmpty() : cachedManager.myInjectorsClone;
   } finally {
     cachedManager.myInjectorsClone.clear();
   }
   cachedManager.myInjectorsClone.putAll(cachedManager.getInjectorMap().getBackingMap());
 }
  @Override
  protected void setUp() throws Exception {
    super.setUp();
    myFilesToDelete.add(new File(FileUtilRt.getTempDirectory()));
    if (ourTestCase != null) {
      String message =
          "Previous test "
              + ourTestCase
              + " hasn't called tearDown(). Probably overridden without super call.";
      ourTestCase = null;
      fail(message);
    }
    IdeaLogger.ourErrorsOccurred = null;

    LOG.info(getClass().getName() + ".setUp()");

    initApplication();

    myEditorListenerTracker = new EditorListenerTracker();
    myThreadTracker = new ThreadTracker();

    setUpProject();

    storeSettings();
    ourTestCase = this;
    if (myProject != null) {
      ProjectManagerEx.getInstanceEx().openTestProject(myProject);
      CodeStyleSettingsManager.getInstance(myProject).setTemporarySettings(new CodeStyleSettings());
      InjectedLanguageManagerImpl.pushInjectors(getProject());
    }

    DocumentCommitThread.getInstance().clearQueue();
    UIUtil.dispatchAllInvocationEvents();
  }
  @Override
  public void setUp() throws Exception {
    super.setUp();

    initApplication();
    setUpProject();

    EncodingManager.getInstance(); // adds listeners
    myEditorListenerTracker = new EditorListenerTracker();
    myThreadTracker = new ThreadTracker();
    InjectedLanguageManagerImpl.pushInjectors(getProject());
  }
  @Override
  public void tearDown() throws Exception {
    Project project = getProject();
    LightPlatformTestCase.doTearDown(project, myApplication, false);

    for (ModuleFixtureBuilder moduleFixtureBuilder : myModuleFixtureBuilders) {
      moduleFixtureBuilder.getFixture().tearDown();
    }
    UIUtil.invokeAndWaitIfNeeded(
        new Runnable() {
          @Override
          public void run() {
            ApplicationManager.getApplication()
                .runWriteAction(
                    new Runnable() {
                      @Override
                      public void run() {
                        Disposer.dispose(myProject);
                        myProject = null;
                      }
                    });
          }
        });

    for (final File fileToDelete : myFilesToDelete) {
      boolean deleted = FileUtil.delete(fileToDelete);
      assert deleted : "Can't delete " + fileToDelete;
    }

    super.tearDown();

    myEditorListenerTracker.checkListenersLeak();
    myThreadTracker.checkLeak();
    LightPlatformTestCase.checkEditorsReleased();
    InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project);
  }
  @NotNull
  private Set<PsiFile> getInjectedPsiFiles(
      @NotNull final List<PsiElement> elements1,
      @NotNull final List<PsiElement> elements2,
      @NotNull final ProgressIndicator progress) {
    ApplicationManager.getApplication().assertReadAccessAllowed();
    final Set<PsiFile> outInjected = new THashSet<PsiFile>();

    List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile);
    final Collection<PsiElement> hosts =
        new THashSet<PsiElement>(elements1.size() + elements2.size() + injected.size());

    // rehighlight all injected PSI regardless the range,
    // since change in one place can lead to invalidation of injected PSI in (completely) other
    // place.
    for (DocumentWindow documentRange : injected) {
      progress.checkCanceled();
      if (!documentRange.isValid()) continue;
      PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange);
      if (file == null) continue;
      PsiElement context =
          InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file);
      if (context != null
          && context.isValid()
          && !file.getProject().isDisposed()
          && (myUpdateAll || myRestrictRange.intersects(context.getTextRange()))) {
        hosts.add(context);
      }
    }
    InjectedLanguageManagerImpl injectedLanguageManager =
        InjectedLanguageManagerImpl.getInstanceImpl(myProject);
    Processor<PsiElement> collectInjectableProcessor =
        new CommonProcessors.CollectProcessor<PsiElement>(hosts);
    injectedLanguageManager.processInjectableElements(elements1, collectInjectableProcessor);
    injectedLanguageManager.processInjectableElements(elements2, collectInjectableProcessor);

    final PsiLanguageInjectionHost.InjectedPsiVisitor visitor =
        new PsiLanguageInjectionHost.InjectedPsiVisitor() {
          @Override
          public void visit(
              @NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
            synchronized (outInjected) {
              outInjected.add(injectedPsi);
            }
          }
        };
    if (!JobLauncher.getInstance()
        .invokeConcurrentlyUnderProgress(
            new ArrayList<PsiElement>(hosts),
            progress,
            true,
            new Processor<PsiElement>() {
              @Override
              public boolean process(PsiElement element) {
                ApplicationManager.getApplication().assertReadAccessAllowed();
                progress.checkCanceled();
                InjectedLanguageUtil.enumerate(element, myFile, false, visitor);
                return true;
              }
            })) {
      throw new ProcessCanceledException();
    }
    synchronized (outInjected) {
      return outInjected;
    }
  }
  @Override
  protected void tearDown() throws Exception {
    List<Throwable> exceptions = new SmartList<Throwable>();
    Project project = myProject;
    if (project != null) {
      try {
        LightPlatformTestCase.doTearDown(project, ourApplication, false, exceptions);
      } catch (Throwable e) {
        exceptions.add(e);
      }

      disposeProject(exceptions);
    }

    try {
      checkForSettingsDamage(exceptions);
    } catch (Throwable e) {
      exceptions.add(e);
    }
    try {
      if (project != null) {
        try {
          InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project);
        } catch (AssertionError e) {
          exceptions.add(e);
        }
      }
      try {
        for (final File fileToDelete : myFilesToDelete) {
          delete(fileToDelete);
        }
        LocalFileSystem.getInstance().refreshIoFiles(myFilesToDelete);
      } catch (Throwable e) {
        exceptions.add(e);
      }

      if (!myAssertionsInTestDetected) {
        if (IdeaLogger.ourErrorsOccurred != null) {
          exceptions.add(IdeaLogger.ourErrorsOccurred);
        }
      }

      try {
        super.tearDown();
      } catch (Throwable e) {
        exceptions.add(e);
      }

      try {
        if (myEditorListenerTracker != null) {
          myEditorListenerTracker.checkListenersLeak();
        }
      } catch (AssertionError error) {
        exceptions.add(error);
      }
      try {
        if (myThreadTracker != null) {
          myThreadTracker.checkLeak();
        }
      } catch (AssertionError error) {
        exceptions.add(error);
      }
      try {
        LightPlatformTestCase.checkEditorsReleased(exceptions);
      } catch (Throwable error) {
        exceptions.add(error);
      }
    } finally {
      myProjectManager = null;
      myProject = null;
      myModule = null;
      myFilesToDelete.clear();
      myEditorListenerTracker = null;
      myThreadTracker = null;
      ourTestCase = null;
    }
    CompoundRuntimeException.throwIfNotEmpty(exceptions);
  }
  private static MultiHostRegistrarImpl probeElementsUp(
      @NotNull PsiElement element, @NotNull PsiFile hostPsiFile, boolean probeUp) {
    PsiManager psiManager = hostPsiFile.getManager();
    final Project project = psiManager.getProject();
    InjectedLanguageManagerImpl injectedManager =
        InjectedLanguageManagerImpl.getInstanceImpl(project);
    if (injectedManager == null) {
      return null; // for tests
    }
    MultiHostRegistrarImpl registrar = null;
    PsiElement current = element;
    nextParent:
    while (current != null && current != hostPsiFile) {
      ProgressManager.checkCanceled();
      if ("EL".equals(current.getLanguage().getID())) break;
      ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> data =
          current.getUserData(INJECTED_PSI);
      if (data == null) {
        registrar =
            InjectedPsiCachedValueProvider.doCompute(
                current, injectedManager, project, hostPsiFile);
      } else {
        registrar = data.getValue(current);
      }

      current = current.getParent(); // cache no injection for current

      if (registrar != null) {
        List<Pair<Place, PsiFile>> places = registrar.getResult();
        // check that injections found intersect with queried element
        TextRange elementRange = element.getTextRange();
        for (Pair<Place, PsiFile> pair : places) {
          Place place = pair.first;
          for (PsiLanguageInjectionHost.Shred shred : place) {
            if (shred.getHost().getTextRange().intersects(elementRange)) {
              if (place.isValid()) break nextParent;
            }
          }
        }
      }
      if (!probeUp) {
        break;
      }
    }

    if (probeUp) {
      // cache only if we walked all parents
      for (PsiElement e = element;
          e != current && e != null && e != hostPsiFile;
          e = e.getParent()) {
        ProgressManager.checkCanceled();
        if (registrar == null) {
          e.putUserData(INJECTED_PSI, null);
        } else {
          ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> cachedValue =
              CachedValuesManager.getManager(project)
                  .createParameterizedCachedValue(INJECTED_PSI_PROVIDER, false);

          CachedValueProvider.Result<MultiHostRegistrarImpl> result =
              CachedValueProvider.Result.create(
                  registrar, PsiModificationTracker.MODIFICATION_COUNT, registrar);
          ((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>) cachedValue)
              .setValue(result);

          e.putUserData(INJECTED_PSI, cachedValue);
        }
      }
    }
    return registrar;
  }