SerializationManager as preloaded service, flat initialization of FileBasedIndexImpl...
authorVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Fri, 30 Aug 2019 17:14:41 +0000 (19:14 +0200)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Fri, 30 Aug 2019 19:31:09 +0000 (19:31 +0000)
GitOrigin-RevId: 9d631b4c8b2a88f71cb5576a5aea7139e9cf14ea

16 files changed:
platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java
platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java
platform/indexing-api/src/com/intellij/psi/stubs/SerializationManager.java
platform/indexing-api/src/com/intellij/psi/stubs/StubIndex.java
platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java
platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java
platform/platform-resources/src/META-INF/LangExtensions.xml
platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
platform/platform-resources/src/META-INF/PlatformExtensions.xml
platform/platform-resources/src/componentSets/Lang.xml
platform/platform-resources/src/componentSets/Platform.xml
platform/projectModel-api/src/com/intellij/openapi/project/ProjectCloseHandler.java [new file with mode: 0644]
platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java

index f804fa30c4952850e9a5a00c9870e7e244bee699..e95ab9eeae4000b92073da33bda1eef60ec893ce 100644 (file)
@@ -1,18 +1,4 @@
-/*
- * Copyright 2000-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.openapi.fileEditor;
 
 import com.intellij.openapi.application.Application;
@@ -34,17 +20,17 @@ import org.jetbrains.annotations.Nullable;
 public abstract class FileDocumentManager implements SavingRequestor {
   @NotNull
   public static FileDocumentManager getInstance() {
-    return ApplicationManager.getApplication().getComponent(FileDocumentManager.class);
+    return ApplicationManager.getApplication().getService(FileDocumentManager.class);
   }
 
   /**
    * Returns the document for the specified virtual file.<p/>
-   * 
+   *
    * Documents are cached on weak or strong references, depending on the nature of the virtual file. If the document for the given virtual file is not yet cached,
    * the file's contents are read from VFS and loaded into heap memory. An appropriate encoding is used. All line separators are converted to {@code \n}.<p/>
-   * 
+   *
    * Should be invoked in a read action.
-   * 
+   *
    * @param file the file for which the document is requested.
    * @return the document, or null if the file represents a directory, or is binary without an associated decompiler,
    * or is too large.
@@ -56,7 +42,7 @@ public abstract class FileDocumentManager implements SavingRequestor {
 
   /**
    * Returns the document for the specified file which has already been loaded into memory.<p/>
-   * 
+   *
    * Client code shouldn't normally use this method, because it's unpredictable and any garbage collection can result in it returning null.
    *
    * @param file the file for which the document is requested.
@@ -78,7 +64,7 @@ public abstract class FileDocumentManager implements SavingRequestor {
    * Saves all unsaved documents to disk. This operation can modify documents that will be saved
    * (due to 'Strip trailing spaces on Save' functionality). When saving, {@code \n} line separators are converted into
    * the ones used normally on the system, or the ones explicitly specified by the user. Encoding settings are honored.<p/>
-   * 
+   *
    * Should be invoked on the event dispatch thread.
    */
   public abstract void saveAllDocuments();
@@ -87,7 +73,7 @@ public abstract class FileDocumentManager implements SavingRequestor {
    * Saves the specified document to disk. This operation can modify the document (due to 'Strip
    * trailing spaces on Save' functionality). When saving, {@code \n} line separators are converted into
    * the ones used normally on the system, or the ones explicitly specified by the user. Encoding settings are honored.<p/>
-   * 
+   *
    * Should be invoked on the event dispatch thread.
    * @param document the document to save.
    */
@@ -95,9 +81,9 @@ public abstract class FileDocumentManager implements SavingRequestor {
 
   /**
    * Saves the document without stripping the trailing spaces or adding a blank line in the end of the file.<p/>
-   * 
+   *
    * Should be invoked on the event dispatch thread.
-   * 
+   *
    * @param document the document to save.
    */
   public abstract void saveDocumentAsIs(@NotNull Document document);
index cf17788fcd62ea57579d74ce90cebe6209c9af02..929599ca6feadb7fedfc10160d2a7ee5adceb703 100644 (file)
@@ -89,9 +89,9 @@ public class CoreApplicationEnvironment {
     myJarFileSystem = createJarFileSystem();
     myJrtFileSystem = createJrtFileSystem();
 
-    final MutablePicoContainer appContainer = myApplication.getPicoContainer();
-    registerComponentInstance(appContainer, FileDocumentManager.class, new MockFileDocumentManagerImpl(
-      charSequence -> new DocumentImpl(charSequence), null));
+    registerApplicationService(FileDocumentManager.class, new MockFileDocumentManagerImpl(charSequence -> {
+      return new DocumentImpl(charSequence);
+    }, null));
 
     List<VirtualFileSystem> fs = myJrtFileSystem != null
                              ? Arrays.asList(myLocalFileSystem, myJarFileSystem, myJrtFileSystem)
index 4d25b27dd921f6688d51809040922091f5a3052f..a2caac1309b7add9d5276ec891bc7ad96da7d493 100644 (file)
@@ -1,22 +1,4 @@
-/*
- * Copyright 2000-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * @author max
- */
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.psi.stubs;
 
 import com.intellij.openapi.application.ApplicationManager;
@@ -30,7 +12,7 @@ public abstract class SerializationManager {
   private volatile boolean mySerializersLoaded;
 
   public static SerializationManager getInstance() {
-    return ApplicationManager.getApplication().getComponent(SerializationManager.class);
+    return ApplicationManager.getApplication().getService(SerializationManager.class);
   }
 
   public void registerSerializer(ObjectStubSerializer serializer) {
index 5dc3e504430025602c6c7486e2abd74d07b882db..18890d2a3497f927d0f2eb725d4424680d823ac4 100644 (file)
@@ -1,18 +1,4 @@
-/*
- * Copyright 2000-2016 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 
 /*
  * @author max
@@ -37,7 +23,7 @@ import java.util.List;
 
 public abstract class StubIndex {
   private static class StubIndexHolder {
-    private static final StubIndex ourInstance = ApplicationManager.getApplication().getComponent(StubIndex.class);
+    private static final StubIndex ourInstance = ApplicationManager.getApplication().getService(StubIndex.class);
   }
   public static StubIndex getInstance() {
     return StubIndexHolder.ourInstance;
index e45550b5363d8a8fcc27b2ba04297eccca19c03f..743c0e834e4fa4e135126663686214d8a5b3db57 100644 (file)
@@ -1,18 +1,4 @@
-/*
- * Copyright 2000-2019 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.util.indexing;
 
 import com.intellij.openapi.application.ApplicationManager;
@@ -60,7 +46,7 @@ public abstract class FileBasedIndex {
   public abstract void removeIndexableSet(@NotNull IndexableFileSet set);
 
   public static FileBasedIndex getInstance() {
-    return ApplicationManager.getApplication().getComponent(FileBasedIndex.class);
+    return ApplicationManager.getApplication().getService(FileBasedIndex.class);
   }
 
   public static int getFileId(@NotNull final VirtualFile file) {
index be75cb41dee6a0065f3d3c23f674bee6f7afc242..7e39a131a9cc0648ab4242bf9c9b8398fde5d488 100644 (file)
@@ -26,7 +26,9 @@ import com.intellij.util.Processor;
 import com.intellij.util.Processors;
 import com.intellij.util.indexing.*;
 import com.intellij.util.indexing.hash.MergedInvertedIndex;
-import com.intellij.util.indexing.impl.*;
+import com.intellij.util.indexing.impl.InputDataDiffBuilder;
+import com.intellij.util.indexing.impl.MapInputDataDiffBuilder;
+import com.intellij.util.indexing.impl.UpdateData;
 import com.intellij.util.indexing.provided.ProvidedIndexExtension;
 import com.intellij.util.io.DataExternalizer;
 import com.intellij.util.io.DataInputOutputUtil;
@@ -51,7 +53,7 @@ import java.util.concurrent.locks.ReadWriteLock;
   @Storage(value = StoragePathMacros.CACHE_FILE),
   @Storage(value = "stubIndex.xml", deprecated = true, roamingType = RoamingType.DISABLED)
 })
-public class StubIndexImpl extends StubIndex implements PersistentStateComponent<StubIndexState> {
+public final class StubIndexImpl extends StubIndex implements PersistentStateComponent<StubIndexState> {
   private static final AtomicReference<Boolean> ourForcedClean = new AtomicReference<>(null);
   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubIndexImpl");
 
@@ -68,8 +70,8 @@ public class StubIndexImpl extends StubIndex implements PersistentStateComponent
 
   private StubIndexState myPreviouslyRegistered;
 
-  public StubIndexImpl(FileBasedIndex fileBasedIndex) {
-    myStubProcessingHelper = new StubProcessingHelper(fileBasedIndex);
+  public StubIndexImpl() {
+    myStubProcessingHelper = new StubProcessingHelper(FileBasedIndex.getInstance());
   }
 
   @Nullable
index a4e081845eb8d95055323fec5231196a74bd8cb9..e54f4a4d2d156edb53b5a3bbaf6671f60f24cc11 100644 (file)
@@ -71,7 +71,6 @@ import com.intellij.util.indexing.provided.ProvidedIndexExtensionLocator;
 import com.intellij.util.io.DataOutputStream;
 import com.intellij.util.io.IOUtil;
 import com.intellij.util.io.storage.HeavyProcessLatch;
-import com.intellij.util.messages.MessageBus;
 import com.intellij.util.messages.MessageBusConnection;
 import com.intellij.util.ui.UIUtil;
 import gnu.trove.THashMap;
@@ -164,15 +163,12 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab
     return state;
   }
 
-  public FileBasedIndexImpl(Application application, VirtualFileManager vfManager,
-                            FileDocumentManager fdm,
-                            FileTypeManagerImpl fileTypeManager,
-                            @NotNull MessageBus bus, ManagingFS managingFS) {
-    myFileDocumentManager = fdm;
-    myFileTypeManager = fileTypeManager;
-    myIsUnitTestMode = application.isUnitTestMode();
+  public FileBasedIndexImpl() {
+    myFileDocumentManager = FileDocumentManager.getInstance();
+    myFileTypeManager = ((FileTypeManagerImpl)FileTypeManager.getInstance());
+    myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode();
 
-    final MessageBusConnection connection = bus.connect();
+    MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect();
     connection.subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() {
       @Override
       public void transactionStarted(@NotNull final Document doc, @NotNull final PsiFile file) {
@@ -255,17 +251,17 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab
       }
     });
 
-    application.addApplicationListener(new ApplicationListener() {
+    ApplicationManager.getApplication().addApplicationListener(new ApplicationListener() {
       @Override
       public void writeActionStarted(@NotNull Object action) {
         myUpToDateIndicesForUnsavedOrTransactedDocuments.clear();
       }
     }, this);
 
-    myChangedFilesCollector = new ChangedFilesCollector(managingFS);
+    myChangedFilesCollector = new ChangedFilesCollector(ManagingFS.getInstance());
     myConnection = connection;
 
-    vfManager.addAsyncFileListener(myChangedFilesCollector, this);
+    VirtualFileManager.getInstance().addAsyncFileListener(myChangedFilesCollector, this);
 
     initComponent();
   }
@@ -2411,7 +2407,6 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab
     private final IndexConfiguration state = new IndexConfiguration();
     private final Set<ID<?, ?>> versionChangedIndexes = ContainerUtil.newConcurrentSet();
     private boolean currentVersionCorrupted;
-    private SerializationManagerEx mySerializationManagerEx;
 
     private void initAssociatedDataForExtensions() {
       Activity activity = ParallelActivity.PREPARE_APP_INIT.start("file index extensions iteration");
@@ -2463,7 +2458,6 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab
     protected void prepare() {
       initAssociatedDataForExtensions();
 
-      mySerializationManagerEx = SerializationManagerEx.getInstanceEx();
       File indexRoot = PathManager.getIndexRoot();
 
       PersistentIndicesConfiguration.loadConfiguration();
@@ -2474,7 +2468,7 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab
         FileUtil.deleteWithRenaming(indexRoot);
         indexRoot.mkdirs();
         // serialization manager is initialized before and use removed index root so we need to reinitialize it
-        mySerializationManagerEx.reinitializeNameStorage();
+        SerializationManagerEx.getInstanceEx().reinitializeNameStorage();
         ID.reinitializeDiskStorage();
         PersistentIndicesConfiguration.saveConfiguration();
         FileUtil.delete(corruptionMarker);
@@ -2526,11 +2520,12 @@ public final class FileBasedIndexImpl extends FileBasedIndex implements Disposab
         saveRegisteredIndicesAndDropUnregisteredOnes(state.getIndexIDs());
 
         myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() {
+          private final SerializationManagerEx mySerializationManager = SerializationManagerEx.getInstanceEx();
           private int lastModCount;
 
           @Override
           public void run() {
-            mySerializationManagerEx.flushNameStorage();
+            mySerializationManager.flushNameStorage();
 
             int currentModCount = myLocalModCount.get();
             if (lastModCount == currentModCount) {
index 253f368e92e1b3ca9652484a545caa0e77340b43..fd22ebb9b0416086a0cf7c4f7dfa6d4c7cfbd074 100644 (file)
@@ -71,7 +71,7 @@ import java.nio.charset.Charset;
 import java.util.List;
 import java.util.*;
 
-public class FileDocumentManagerImpl extends FileDocumentManager implements AsyncFileListener, VetoableProjectManagerListener, SafeWriteRequestor {
+public class FileDocumentManagerImpl extends FileDocumentManager implements SafeWriteRequestor {
   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl");
 
   public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
@@ -119,11 +119,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Asyn
   };
 
   public FileDocumentManagerImpl() {
-    VirtualFileManager.getInstance().addAsyncFileListener(this, ApplicationManager.getApplication());
-    ProjectManager.getInstance().addProjectManagerListener(this);
-
     myBus = ApplicationManager.getApplication().getMessageBus();
-    myBus.connect().subscribe(ProjectManager.TOPIC, this);
 
     InvocationHandler handler = (proxy, method, args) -> {
       multiCast(method, args);
@@ -134,6 +130,23 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Asyn
     myMultiCaster = (FileDocumentManagerListener)Proxy.newProxyInstance(loader, new Class[]{FileDocumentManagerListener.class}, handler);
   }
 
+  static final class MyProjectCloseHandler implements ProjectCloseHandler {
+    @Override
+    public boolean canClose(@NotNull Project project) {
+      FileDocumentManagerImpl manager = (FileDocumentManagerImpl)getInstance();
+      if (!manager.myUnsavedDocuments.isEmpty()) {
+        manager.myOnClose = true;
+        try {
+          manager.saveAllDocuments();
+        }
+        finally {
+          manager.myOnClose = false;
+        }
+      }
+      return manager.myUnsavedDocuments.isEmpty();
+    }
+  }
+
   private static void unwrapAndRethrow(@NotNull Exception e) {
     Throwable unwrapped = e;
     if (e instanceof InvocationTargetException) {
@@ -596,71 +609,77 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Asyn
     return fileType.isBinary() && BinaryFileTypeDecompilers.getInstance().forFileType(fileType) == null;
   }
 
-  @Override
-  public ChangeApplier prepareChange(@NotNull List<? extends VFileEvent> events) {
-    List<VirtualFile> toRecompute = new ArrayList<>();
-    Map<VirtualFile, Document> strongRefsToDocuments = new HashMap<>();
-    List<VFileContentChangeEvent> contentChanges = ContainerUtil.findAll(events, VFileContentChangeEvent.class);
-    for (VFileContentChangeEvent event : contentChanges) {
-      ProgressManager.checkCanceled();
-      VirtualFile virtualFile = event.getFile();
-
-      // when an empty unknown file is written into, re-run file type detection
-      long lastRecordedLength = PersistentFS.getInstance().getLastRecordedLength(virtualFile);
-      if (lastRecordedLength == 0 && FileTypeRegistry.getInstance().isFileOfType(virtualFile, UnknownFileType.INSTANCE)) { // check file type last to avoid content detection running
-        toRecompute.add(virtualFile);
-      }
-
-      prepareForRangeMarkerUpdate(strongRefsToDocuments, virtualFile);
-    }
+  static final class MyAsyncFileListener implements AsyncFileListener {
+    private final FileDocumentManagerImpl myFileDocumentManager = (FileDocumentManagerImpl)getInstance();
 
-    return new ChangeApplier() {
-      @Override
-      public void beforeVfsChange() {
-        for (VFileContentChangeEvent event : contentChanges) {
-          // new range markers could've appeared after "prepareChange" in some read action
-          prepareForRangeMarkerUpdate(strongRefsToDocuments, event.getFile());
-          if (ourConflictsSolverEnabled) {
-            myConflictResolver.beforeContentChange(event);
-          }
+    @Override
+    public ChangeApplier prepareChange(@NotNull List<? extends VFileEvent> events) {
+      List<VirtualFile> toRecompute = new ArrayList<>();
+      Map<VirtualFile, Document> strongRefsToDocuments = new HashMap<>();
+      List<VFileContentChangeEvent> contentChanges = ContainerUtil.findAll(events, VFileContentChangeEvent.class);
+      for (VFileContentChangeEvent event : contentChanges) {
+        ProgressManager.checkCanceled();
+        VirtualFile virtualFile = event.getFile();
+
+        // when an empty unknown file is written into, re-run file type detection
+        long lastRecordedLength = PersistentFS.getInstance().getLastRecordedLength(virtualFile);
+        if (lastRecordedLength == 0 &&
+            FileTypeRegistry.getInstance()
+              .isFileOfType(virtualFile, UnknownFileType.INSTANCE)) { // check file type last to avoid content detection running
+          toRecompute.add(virtualFile);
         }
 
-        for (VirtualFile file : toRecompute) {
-          file.putUserData(MUST_RECOMPUTE_FILE_TYPE, Boolean.TRUE);
-        }
+        prepareForRangeMarkerUpdate(strongRefsToDocuments, virtualFile);
       }
 
-      @Override
-      public void afterVfsChange() {
-        for (VFileEvent event : events) {
-          VirtualFile file = event.getFile();
-          if (file != null && !file.isValid()) continue;
-
-          if (event instanceof VFileContentChangeEvent) {
-            contentsChanged((VFileContentChangeEvent)event);
-          }
-          else if (event instanceof VFileDeleteEvent) {
-            fileDeleted((VFileDeleteEvent)event);
+      return new ChangeApplier() {
+        @Override
+        public void beforeVfsChange() {
+          for (VFileContentChangeEvent event : contentChanges) {
+            // new range markers could've appeared after "prepareChange" in some read action
+            prepareForRangeMarkerUpdate(strongRefsToDocuments, event.getFile());
+            if (ourConflictsSolverEnabled) {
+              myFileDocumentManager.myConflictResolver.beforeContentChange(event);
+            }
           }
-          else if (event instanceof VFilePropertyChangeEvent) {
-            propertyChanged((VFilePropertyChangeEvent)event);
+
+          for (VirtualFile file : toRecompute) {
+            file.putUserData(MUST_RECOMPUTE_FILE_TYPE, Boolean.TRUE);
           }
         }
-        ObjectUtils.reachabilityFence(strongRefsToDocuments);
-      }
-    };
-  }
 
-  private void prepareForRangeMarkerUpdate(Map<VirtualFile, Document> strongRefsToDocuments, VirtualFile virtualFile) {
-    Document document = getCachedDocument(virtualFile);
-    if (document == null && DocumentImpl.areRangeMarkersRetainedFor(virtualFile)) {
-      // re-create document with the old contents prior to this event
-      // then contentChanged() will diff the document with the new contents and update the markers
-      document = getDocument(virtualFile);
+        @Override
+        public void afterVfsChange() {
+          for (VFileEvent event : events) {
+            VirtualFile file = event.getFile();
+            if (file != null && !file.isValid()) continue;
+
+            if (event instanceof VFileContentChangeEvent) {
+              myFileDocumentManager.contentsChanged((VFileContentChangeEvent)event);
+            }
+            else if (event instanceof VFileDeleteEvent) {
+              myFileDocumentManager.fileDeleted((VFileDeleteEvent)event);
+            }
+            else if (event instanceof VFilePropertyChangeEvent) {
+              myFileDocumentManager.propertyChanged((VFilePropertyChangeEvent)event);
+            }
+          }
+          ObjectUtils.reachabilityFence(strongRefsToDocuments);
+        }
+      };
     }
-    // save document strongly to make it live until contentChanged()
-    if (document != null) {
-      strongRefsToDocuments.put(virtualFile, document);
+
+    private void prepareForRangeMarkerUpdate(Map<VirtualFile, Document> strongRefsToDocuments, VirtualFile virtualFile) {
+      Document document = myFileDocumentManager.getCachedDocument(virtualFile);
+      if (document == null && DocumentImpl.areRangeMarkersRetainedFor(virtualFile)) {
+        // re-create document with the old contents prior to this event
+        // then contentChanged() will diff the document with the new contents and update the markers
+        document = myFileDocumentManager.getDocument(virtualFile);
+      }
+      // save document strongly to make it live until contentChanged()
+      if (document != null) {
+        strongRefsToDocuments.put(virtualFile, document);
+      }
     }
   }
 
@@ -755,20 +774,6 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Asyn
     return false;
   }
 
-  @Override
-  public boolean canClose(@NotNull Project project) {
-    if (!myUnsavedDocuments.isEmpty()) {
-      myOnClose = true;
-      try {
-        saveAllDocuments();
-      }
-      finally {
-        myOnClose = false;
-      }
-    }
-    return myUnsavedDocuments.isEmpty();
-  }
-
   private void fireUnsavedDocumentsDropped() {
     myMultiCaster.unsavedDocumentsDropped();
   }
index 416edbf7c3a5c96912b58af32bb800f8c70c83df..549253756199192c4d9b417814b98397e382fc11 100644 (file)
@@ -26,6 +26,7 @@ import com.intellij.openapi.components.ComponentManager;
 import com.intellij.openapi.components.ProjectComponent;
 import com.intellij.openapi.diagnostic.Attachment;
 import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.extensions.ExtensionPointName;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
 import com.intellij.openapi.progress.ProcessCanceledException;
 import com.intellij.openapi.progress.ProgressIndicator;
@@ -74,6 +75,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
 
   private static final Key<List<ProjectManagerListener>> LISTENERS_IN_PROJECT_KEY = Key.create("LISTENERS_IN_PROJECT_KEY");
 
+  private static final ExtensionPointName<ProjectCloseHandler> CLOSE_HANDLER_EP = new ExtensionPointName<>("com.intellij.projectCloseHandler");
+
   private @NotNull Project[] myOpenProjects = {}; // guarded by lock
   private final Map<String, Project> myOpenProjectByHash = ContainerUtil.newConcurrentMap();
   private final Object lock = new Object();
@@ -898,10 +901,29 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
       LOG.debug("enter: canClose()");
     }
 
+    for (ProjectCloseHandler handler : CLOSE_HANDLER_EP.getIterable()) {
+      if (handler == null) {
+        break;
+      }
+
+      try {
+        if (!handler.canClose(project)) {
+          LOG.debug("close canceled by " + handler);
+          return false;
+        }
+      }
+      catch (ProcessCanceledException e) {
+        throw e;
+      }
+      catch (Throwable e) {
+        LOG.error(e);
+      }
+    }
+
     for (ProjectManagerListener listener : getAllListeners(project)) {
       try {
-        @SuppressWarnings("deprecation") boolean canClose =
-          listener instanceof VetoableProjectManagerListener ? ((VetoableProjectManagerListener)listener).canClose(project) : listener.canCloseProject(project);
+        @SuppressWarnings("deprecation")
+        boolean canClose = listener instanceof VetoableProjectManagerListener ? ((VetoableProjectManagerListener)listener).canClose(project) : listener.canCloseProject(project);
         if (!canClose) {
           LOG.debug("close canceled by " + listener);
           return false;
index 49564bef477261f2a758f2f009d8768c5c8a0006..b2e74e39e48372ce92578071fd5d3f72c4e908e1 100644 (file)
     <referencesSearch implementation="com.intellij.psi.impl.search.CachesBasedRefSearcher"/>
     <referencesSearch implementation="com.intellij.psi.impl.search.NonPhysicalReferenceSearcher"/>
 
+    <!-- FileBasedIndex / SerializationManager is quite important and in any case will be used, better to preload it -->
+    <applicationService serviceInterface="com.intellij.util.indexing.FileBasedIndex"
+                        serviceImplementation="com.intellij.util.indexing.FileBasedIndexImpl" preload="true"/>
+    <applicationService serviceInterface="com.intellij.psi.stubs.SerializationManager"
+                        serviceImplementation="com.intellij.psi.stubs.SerializationManagerImpl" preload="true"/>
+    <applicationService serviceInterface="com.intellij.psi.stubs.StubIndex"
+                        serviceImplementation="com.intellij.psi.stubs.StubIndexImpl" preload="true"/>
+
     <applicationService serviceInterface="com.intellij.codeInsight.completion.CompletionService"
                         serviceImplementation="com.intellij.codeInsight.completion.impl.CompletionServiceImpl"/>
 
index 0a40576151c99b31ea210050d1746ab4e3ed35a4..4a1df1efd30623352a1591e86c26fe362f5fd259 100644 (file)
     <extensionPoint name="editorFactoryMouseListener" interface="com.intellij.openapi.editor.event.EditorMouseListener"/>
     <extensionPoint name="editorFactoryMouseMotionListener" interface="com.intellij.openapi.editor.event.EditorMouseMotionListener"/>
     <extensionPoint name="editorFactoryListener" interface="com.intellij.openapi.editor.event.EditorFactoryListener"/>
+
+    <extensionPoint name="projectCloseHandler" interface="com.intellij.openapi.project.ProjectCloseHandler"/>
   </extensionPoints>
 </idea-plugin>
index bf48e29763b0e5faf15e06bed18766eba8baabfa..2a06ae445206b1ef4dfea847b6c286cd2ad65e7f 100644 (file)
     <applicationService serviceInterface="com.intellij.openapi.keymap.KeymapManager" preload="true"
                         serviceImplementation="com.intellij.openapi.keymap.impl.KeymapManagerImpl"/>
 
+    <!-- requested by FileBasedIndexImpl, so, to make start-up more flat, also preload -->
+    <applicationService serviceInterface="com.intellij.openapi.fileEditor.FileDocumentManager" preload="true"
+                        serviceImplementation="com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl"/>
+    <projectCloseHandler implementation="com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl$MyProjectCloseHandler"/>
+    <vfs.asyncListener implementation="com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl$MyAsyncFileListener"/>
+
     <applicationService serviceInterface="com.intellij.openapi.project.ProjectManager"
                         serviceImplementation="com.intellij.openapi.project.impl.ProjectManagerImpl"/>
 
index ac0282f81834286bbfbedfe438ab5d925b82c68b..97772ebf3f22dcca82ac6dfcb1f58f33a2eac737 100644 (file)
@@ -1,20 +1,4 @@
 <idea-plugin>
-  <application-components>
-    <component>
-      <interface-class>com.intellij.util.indexing.FileBasedIndex</interface-class>
-      <implementation-class>com.intellij.util.indexing.FileBasedIndexImpl</implementation-class>
-    </component>
-    <component>
-      <interface-class>com.intellij.psi.stubs.StubIndex</interface-class>
-      <implementation-class>com.intellij.psi.stubs.StubIndexImpl</implementation-class>
-    </component>
-
-    <component>
-      <interface-class>com.intellij.psi.stubs.SerializationManager</interface-class>
-      <implementation-class>com.intellij.psi.stubs.SerializationManagerImpl</implementation-class>
-    </component>
-  </application-components>
-
   <project-components>
     <component>
       <interface-class>com.intellij.openapi.roots.ProjectRootManager</interface-class>
index 1fe664b617d495bc3c4a99d1dea476d8849c7568..669cdc4432f2bc75e4186738a01df972197bf2a6 100644 (file)
     </component>
 
     <component>
-      <interface-class>com.intellij.openapi.fileEditor.FileDocumentManager</interface-class>
-      <implementation-class>com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl</implementation-class>
-    </component>
-
-    <component>
       <interface-class>com.intellij.openapi.command.undo.UndoManager</interface-class>
       <implementation-class>com.intellij.openapi.command.impl.UndoManagerImpl</implementation-class>
     </component>
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectCloseHandler.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectCloseHandler.java
new file mode 100644 (file)
index 0000000..e7bee9c
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.project;
+
+import org.jetbrains.annotations.NotNull;
+
+public interface ProjectCloseHandler {
+  /**
+   * Checks whether the project can be closed.
+   *
+   * @param project project to check
+   * @return true or false
+   */
+  boolean canClose(@NotNull Project project);
+}
index fe81c601fc30c7ddf29ea23b1721faa16604a2c5..375ad5b973e1e4dcbb5877f817b4731c44b12148 100644 (file)
@@ -105,7 +105,7 @@ public abstract class ParsingTestCase extends UsefulTestCase {
     appContainer.registerComponentInstance(SchemeManagerFactory.class, new MockSchemeManagerFactory());
     MockEditorFactory editorFactory = new MockEditorFactory();
     appContainer.registerComponentInstance(EditorFactory.class, editorFactory);
-    appContainer.registerComponentInstance(FileDocumentManager.class, new MockFileDocumentManagerImpl(charSequence -> {
+    app.registerService(FileDocumentManager.class, new MockFileDocumentManagerImpl(charSequence -> {
       return editorFactory.createDocument(charSequence);
     }, FileDocumentManagerImpl.HARD_REF_TO_DOCUMENT_KEY));
     appContainer.registerComponentInstance(PsiDocumentManager.class, new MockPsiDocumentManager());