From 57f7e14ea50febc25b5e90d3cdf3610b765bc328 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sat, 16 Jul 2022 09:25:55 +0200 Subject: [PATCH] don't schedule post-start-up activities under modal progress GitOrigin-RevId: 2ac572b66cf0ad8bc28a5713bc71967a8700f19d --- .../compiler/CompilerConfigurationImpl.java | 4 +- .../UnloadedModulesCompilationTest.kt | 156 ++++++++-------- .../progress/CompilerBuildViewTest.kt | 21 +-- .../jshell/SnippetEditorDecorator.java | 2 +- .../configurationStore/LoadProjectTest.kt | 4 +- .../configurationStore/SaveProjectTest.kt | 6 +- .../DirectoryIndexForUnloadedModuleTest.kt | 88 ++++----- .../actions/ModuleDeleteProviderTest.java | 9 +- .../projectView/ModulesInProjectViewTest.kt | 31 ++-- .../roots/UnloadedModulesConfigurationTest.kt | 33 ++-- .../PrecomputedExtensionModel.kt | 4 +- .../project/manage/SourceFolderManagerImpl.kt | 10 +- .../project/manage/SourceFolderManagerTest.kt | 4 +- .../messages/ProjectBundle.properties | 1 - .../intellij/openapi/project/ProjectUtil.kt | 2 +- .../facet/impl/FacetEventsPublisher.kt | 9 +- .../facet/impl/ProjectFacetManagerImpl.java | 4 +- .../pointers/FacetPointerModuleListener.java | 14 +- .../impl/AutomaticModuleUnloaderImpl.kt | 5 +- .../openapi/module/impl/ModuleImpl.java | 23 ++- .../impl/ProjectRootManagerComponent.java | 13 +- .../ConfigureUnloadedModulesDialog.kt | 6 +- .../legacyBridge/module/ModuleBridgeImpl.kt | 13 +- .../module/ModuleBridgeLoaderService.kt | 58 +++--- .../module/ModuleManagerComponentBridge.kt | 61 +++--- .../roots/ModuleDependencyInRootModelTest.kt | 10 +- .../intellij/openapi/roots/ModuleModelTest.kt | 6 +- .../resources/messages/IdeBundle.properties | 1 - .../com/intellij/ide/RecentProjectMetaInfo.kt | 6 +- .../intellij/ide/RecentProjectsManagerBase.kt | 60 +++--- .../src/com/intellij/ide/SwingCleanuper.java | 173 ------------------ .../convertModuleGroupsToQualifiedNames.kt | 4 +- .../project/LightEditProjectManager.kt | 135 +++++++------- .../ide/startup/impl/StartupManagerImpl.kt | 87 +++++---- .../com/intellij/idea/ApplicationLoader.kt | 6 +- .../impl/FileEditorManagerImpl.java | 27 ++- .../fileEditor/impl/OpenFilesActivity.kt | 5 + .../openapi/project/impl/ProjectImpl.kt | 3 +- .../project/impl/ProjectManagerImpl.kt | 106 +++++------ .../com/intellij/ui/mac/MacDockDelegate.java | 11 +- .../src/META-INF/LangExtensions.xml | 10 +- .../src/META-INF/PlatformLangComponents.xml | 6 + .../module/ExplicitModuleGroupTest.kt | 18 +- .../project/impl/RecentProjectsTest.kt | 62 ++++--- .../impl/navigation/JBNavigateCommandTest.kt | 8 +- .../indexing/IndexableFilesRegularTest.kt | 7 +- .../impl/indexing/ProjectStructureDsl.kt | 4 +- .../openapi/module/ModuleComponent.java | 16 +- .../intellij/openapi/module/ModuleManager.kt | 151 +++++++-------- .../openapi/project/ModuleListener.java | 8 +- .../project/ProjectManagerListener.java | 1 + .../roots/ex/ProjectRootManagerEx.java | 2 + .../openapi/module/EmptyModuleManager.kt | 24 ++- .../module/impl/ModulePointerManagerImpl.kt | 18 +- .../openapi/module/impl/modulePath.kt | 60 +----- .../roots/impl/ProjectRootManagerImpl.java | 7 +- .../module/ModuleManagerBridgeImpl.kt | 143 +++++++++------ .../com/intellij/module/moduleGroupTests.kt | 18 +- .../intellij/project/TestProjectManager.kt | 17 +- .../testFramework/rules/ProjectModelRule.kt | 4 +- .../vcs/impl/ModuleDefaultVcsRootPolicy.java | 12 +- .../ide/LibraryPropertiesTest.kt | 2 +- .../ide/ModifiableRootModelBridgeTest.kt | 6 +- .../workspaceModel/ide/ModuleBridgesTest.kt | 32 ++-- .../ide/ModuleLibraryBridgeTest.kt | 16 +- .../ide/ProjectLibraryBridgeTest.kt | 4 +- .../ide/WorkspaceModelPerformanceTest.kt | 6 +- .../importing/GradleMiscImportingTest.java | 4 +- .../idea/testFramework/ProjectBuilder.kt | 4 +- .../wizard/NewProjectWizardModuleBuilder.kt | 4 +- .../idea/test/KotlinMultiFileTestCase.kt | 4 +- .../maven/project/MavenProjectsManager.java | 8 +- .../intellij/plugin/util/ProjectExtensions.kt | 2 +- .../psi/impl/PythonLanguageLevelPusher.java | 51 +++--- 74 files changed, 888 insertions(+), 1072 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 334db81b68d8..550699625292 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler; import com.intellij.CommonBundle; @@ -114,7 +114,7 @@ public final class CompilerConfigurationImpl extends CompilerConfiguration imple } @Override - public void moduleAdded(@NotNull Project project, @NotNull Module module) { + public void modulesAdded(@NotNull Project project, @NotNull List modules) { myProcessorsProfilesMap = null; // clear cache } diff --git a/java/compiler/tests/com/intellij/compiler/UnloadedModulesCompilationTest.kt b/java/compiler/tests/com/intellij/compiler/UnloadedModulesCompilationTest.kt index 812e64ee0bff..1f1cd1db821f 100644 --- a/java/compiler/tests/com/intellij/compiler/UnloadedModulesCompilationTest.kt +++ b/java/compiler/tests/com/intellij/compiler/UnloadedModulesCompilationTest.kt @@ -1,96 +1,88 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.compiler; +package com.intellij.compiler -import com.intellij.compiler.impl.ModuleCompileScope; -import com.intellij.configurationStore.StoreUtilKt; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.roots.ModuleRootModificationUtil; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; -import kotlin.Unit; -import org.jetbrains.annotations.NotNull; +import com.intellij.compiler.impl.ModuleCompileScope +import com.intellij.configurationStore.runInAllowSaveMode +import com.intellij.ide.impl.runUnderModalProgressIfIsEdt +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.util.io.TestFileSystemBuilder +import java.io.IOException -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -import static com.intellij.util.io.TestFileSystemBuilder.fs; - -public class UnloadedModulesCompilationTest extends BaseCompilerTestCase { - public void testDoNotCompileUnloadedModulesByDefault() { - VirtualFile a = createFile("unloaded/src/A.java", "class A{ error }"); - Module unloaded = addModule("unloaded", a.getParent()); - List unloadedList = Collections.singletonList(unloaded.getName()); - ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList); - buildAllModules().assertUpToDate(); +class UnloadedModulesCompilationTest : BaseCompilerTestCase() { + fun testDoNotCompileUnloadedModulesByDefault() { + val a = createFile("unloaded/src/A.java", "class A{ error }") + val unloaded = addModule("unloaded", a.parent) + val unloadedList = listOf(unloaded.name) + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList) + } + buildAllModules().assertUpToDate() } - public void testCompileUnloadedModulesIfExplicitlySpecified() { - VirtualFile a = createFile("unloaded/src/A.java", "class A{}"); - Module unloaded = addModule("unloaded", a.getParent()); - File outputDir = getOutputDir(unloaded, false); - - List unloadedList = List.of(unloaded.getName()); - StoreUtilKt.runInAllowSaveMode(true, () -> { - ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList); - return Unit.INSTANCE; - }); - - make(createScopeWithUnloaded(Collections.emptyList(), unloadedList)); - fs().file("A.class").build().assertDirectoryEqual(outputDir); + fun testCompileUnloadedModulesIfExplicitlySpecified() { + val a = createFile("unloaded/src/A.java", "class A{}") + val unloaded = addModule("unloaded", a.parent) + val outputDir = getOutputDir(unloaded, false) + val unloadedList = listOf(unloaded.name) + runInAllowSaveMode(true) { + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList) + } + } + make(createScopeWithUnloaded(emptyList(), unloadedList)) + TestFileSystemBuilder.fs().file("A.class").build().assertDirectoryEqual(outputDir) } - public void testCompileUsagesOfConstantInUnloadedModules() throws IOException { - VirtualFile utilFile = createFile("unloaded/src/Util.java", "class Util { public static final String FOO = \"foo\"; }"); - VirtualFile a = createFile("unloaded/src/A.java", "class A{ { System.out.println(Util.FOO); } }"); - Module unloaded = addModule("unloaded", a.getParent()); - buildAllModules(); - - List unloadedList = Collections.singletonList(unloaded.getName()); - ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList); - - changeFile(utilFile, VfsUtilCore.loadText(utilFile).replace("foo", "foo2")); - - make(createScopeWithUnloaded(Collections.emptyList(), unloadedList)).assertGenerated("A.class", "Util.class"); + @Throws(IOException::class) + fun testCompileUsagesOfConstantInUnloadedModules() { + val utilFile = createFile("unloaded/src/Util.java", "class Util { public static final String FOO = \"foo\"; }") + val a = createFile("unloaded/src/A.java", "class A{ { System.out.println(Util.FOO); } }") + val unloaded = addModule("unloaded", a.parent) + buildAllModules() + val unloadedList = listOf(unloaded.name) + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList) + } + changeFile(utilFile, VfsUtilCore.loadText(utilFile).replace("foo", "foo2")) + make(createScopeWithUnloaded(emptyList(), unloadedList)).assertGenerated("A.class", "Util.class") } - public void testCompileUsagesOfConstantFromNormalModuleInInUnloadedModules() throws IOException { - VirtualFile utilFile = createFile("util/src/Util.java", "class Util { public static final String FOO = \"foo\"; }"); - Module util = addModule("util", utilFile.getParent()); - VirtualFile a = createFile("unloaded/src/A.java", "class A{ { System.out.println(Util.FOO); } }"); - Module unloaded = addModule("unloaded", a.getParent()); - ModuleRootModificationUtil.addDependency(unloaded, util); - buildAllModules(); - - List unloadedList = Collections.singletonList(unloaded.getName()); - ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList); - - changeFile(utilFile, VfsUtilCore.loadText(utilFile).replace("foo", "foo2")); - - make(createScopeWithUnloaded(Collections.singletonList(util), unloadedList)).assertGenerated("A.class", "Util.class"); + @Throws(IOException::class) + fun testCompileUsagesOfConstantFromNormalModuleInInUnloadedModules() { + val utilFile = createFile("util/src/Util.java", "class Util { public static final String FOO = \"foo\"; }") + val util = addModule("util", utilFile.parent) + val a = createFile("unloaded/src/A.java", "class A{ { System.out.println(Util.FOO); } }") + val unloaded = addModule("unloaded", a.parent) + ModuleRootModificationUtil.addDependency(unloaded, util) + buildAllModules() + val unloadedList = listOf(unloaded.name) + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList) + } + changeFile(utilFile, VfsUtilCore.loadText(utilFile).replace("foo", "foo2")) + make(createScopeWithUnloaded(listOf(util), unloadedList)).assertGenerated("A.class", "Util.class") } - public void testCompileUnloadedModuleAfterBuildingAllLoadedModules() { - VirtualFile utilFile = createFile("util/src/Util.java", "class Util { }"); - Module util = addModule("util", utilFile.getParent()); - VirtualFile a = createFile("unloaded/src/A.java", "class A { Util u = new Util(); }"); - Module unloaded = addModule("unloaded", a.getParent()); - ModuleRootModificationUtil.addDependency(unloaded, util); - buildAllModules(); - - List unloadedList = Collections.singletonList(unloaded.getName()); - ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList); - - changeFile(utilFile, "class Util { Util(int i) {} }"); - buildAllModules().assertGenerated("Util.class"); - - compile(createScopeWithUnloaded(Collections.singletonList(util), unloadedList), false, true); + fun testCompileUnloadedModuleAfterBuildingAllLoadedModules() { + val utilFile = createFile("util/src/Util.java", "class Util { }") + val util = addModule("util", utilFile.parent) + val a = createFile("unloaded/src/A.java", "class A { Util u = new Util(); }") + val unloaded = addModule("unloaded", a.parent) + ModuleRootModificationUtil.addDependency(unloaded, util) + buildAllModules() + val unloadedList = listOf(unloaded.name) + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(unloadedList) + } + changeFile(utilFile, "class Util { Util(int i) {} }") + buildAllModules().assertGenerated("Util.class") + compile(createScopeWithUnloaded(listOf(util), unloadedList), false, true) } - @NotNull - private ModuleCompileScope createScopeWithUnloaded(List modules, List unloaded) { - return new ModuleCompileScope(myProject, modules, unloaded, true, false); + private fun createScopeWithUnloaded(modules: List, unloaded: List): ModuleCompileScope { + return ModuleCompileScope(myProject, modules, unloaded, true, false) } -} +} \ No newline at end of file diff --git a/java/compiler/tests/com/intellij/compiler/progress/CompilerBuildViewTest.kt b/java/compiler/tests/com/intellij/compiler/progress/CompilerBuildViewTest.kt index cb5a2bee045d..917e869bbb31 100644 --- a/java/compiler/tests/com/intellij/compiler/progress/CompilerBuildViewTest.kt +++ b/java/compiler/tests/com/intellij/compiler/progress/CompilerBuildViewTest.kt @@ -4,7 +4,6 @@ package com.intellij.compiler.progress import com.intellij.build.BuildWorkspaceConfiguration import com.intellij.compiler.BaseCompilerTestCase import com.intellij.compiler.CompilerWorkspaceConfiguration -import com.intellij.openapi.Disposable import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.compiler.CompilationStatusListener import com.intellij.openapi.compiler.CompileContext @@ -19,17 +18,15 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.util.Disposer import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.PsiTestUtil.addSourceRoot -import com.intellij.testFramework.RunAll +import com.intellij.testFramework.common.runAll import com.intellij.testFramework.fixtures.BuildViewTestFixture -import com.intellij.util.ThrowableRunnable import org.assertj.core.api.Assertions.assertThat import org.jetbrains.jps.model.java.JavaResourceRootType class CompilerBuildViewTest : BaseCompilerTestCase() { private lateinit var buildViewTestFixture: BuildViewTestFixture - private val testDisposable: Disposable = Disposer.newDisposable() + private val testDisposable = Disposer.newDisposable() - @Throws(Exception::class) public override fun setUp() { super.setUp() buildViewTestFixture = BuildViewTestFixture(project) @@ -37,11 +34,11 @@ class CompilerBuildViewTest : BaseCompilerTestCase() { } public override fun tearDown() { - RunAll( - ThrowableRunnable { if (::buildViewTestFixture.isInitialized) buildViewTestFixture.tearDown() }, - ThrowableRunnable { Disposer.dispose(testDisposable) }, - ThrowableRunnable { super.tearDown() } - ).run() + runAll ( + { if (::buildViewTestFixture.isInitialized) buildViewTestFixture.tearDown() }, + { Disposer.dispose(testDisposable) }, + { super.tearDown() } + ) } fun `test empty build`() { @@ -70,7 +67,7 @@ class CompilerBuildViewTest : BaseCompilerTestCase() { runWithProgressExIndicatorSupport { rebuildProject() } buildViewTestFixture.assertBuildViewTreeEquals("-\n rebuild finished") - buildViewTestFixture.assertBuildViewSelectedNode("rebuild finished", false) { output: String? -> + buildViewTestFixture.assertBuildViewSelectedNode("rebuild finished", false) { output -> assertThat(output).startsWith("Clearing build system data...\n" + "Executing pre-compile tasks...\n" + "Cleaning output directories…\n" + @@ -91,7 +88,7 @@ class CompilerBuildViewTest : BaseCompilerTestCase() { runWithProgressExIndicatorSupport { rebuild(module) } buildViewTestFixture.assertBuildViewTreeEquals("-\n recompile finished") - buildViewTestFixture.assertBuildViewSelectedNode("recompile finished", false) { output: String? -> + buildViewTestFixture.assertBuildViewSelectedNode("recompile finished", false) { output -> assertThat(output).startsWith("Executing pre-compile tasks...\n" + "Cleaning output directories…\n" + "Running 'before' tasks\n" + diff --git a/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java b/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java index 65d1854e06c5..b31ae9caa39a 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java @@ -122,7 +122,7 @@ public final class SnippetEditorDecorator implements EditorNotificationProvider myBusConnection = project.getMessageBus().connect(); myBusConnection.subscribe(ProjectTopics.MODULES, new ModuleListener() { @Override - public void moduleAdded(@NotNull Project project, @NotNull Module module) { + public void modulesAdded(@NotNull Project project, @NotNull List modules) { reloadModules(); } diff --git a/java/java-tests/testSrc/com/intellij/java/configurationStore/LoadProjectTest.kt b/java/java-tests/testSrc/com/intellij/java/configurationStore/LoadProjectTest.kt index 96625461314b..07de159bca91 100644 --- a/java/java-tests/testSrc/com/intellij/java/configurationStore/LoadProjectTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/configurationStore/LoadProjectTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.configurationStore import com.intellij.ProjectTopics @@ -78,7 +78,7 @@ class LoadProjectTest { val fooModule = ModuleManager.getInstance(project).modules.single() assertThat(fooModule.name).isEqualTo("foo") runWriteActionAndWait { - val model = ModuleManager.getInstance(project).modifiableModel + val model = ModuleManager.getInstance(project).getModifiableModel() model.loadModule("${project.basePath}/bar/bar.iml") model.commit() } diff --git a/java/java-tests/testSrc/com/intellij/java/configurationStore/SaveProjectTest.kt b/java/java-tests/testSrc/com/intellij/java/configurationStore/SaveProjectTest.kt index f7c7ee709397..249fe68ce4fa 100644 --- a/java/java-tests/testSrc/com/intellij/java/configurationStore/SaveProjectTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/configurationStore/SaveProjectTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.configurationStore import com.intellij.openapi.application.runReadAction @@ -43,7 +43,7 @@ class SaveProjectTest { val module = projectModel.createModule("foo") fun setGroupPath(path: Array?) { runWriteActionAndWait { - val model = projectModel.moduleManager.modifiableModel + val model = projectModel.moduleManager.getModifiableModel() model.setModuleGroupPath(module, path) model.commit() } @@ -84,7 +84,7 @@ class SaveProjectTest { @Test fun `save renamed module`() { - val model = runReadAction { projectModel.moduleManager.modifiableModel } + val model = runReadAction { projectModel.moduleManager.getModifiableModel() } val module = projectModel.createModule("foo", model) model.renameModule(module, "bar") runWriteActionAndWait { model.commit() } diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexForUnloadedModuleTest.kt b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexForUnloadedModuleTest.kt index 26dd2ca123ad..b0ec9a014e26 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexForUnloadedModuleTest.kt +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexForUnloadedModuleTest.kt @@ -1,51 +1,53 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.roots.impl; +package com.intellij.openapi.roots.impl -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.roots.DependencyScope; -import com.intellij.openapi.roots.ModuleRootModificationUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ide.impl.runUnderModalProgressIfIsEdt +import com.intellij.openapi.module.ModuleManager.Companion.getInstance +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.testFramework.HeavyPlatformTestCase +import com.intellij.testFramework.UsefulTestCase +import java.io.IOException +import java.util.* -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -public class DirectoryIndexForUnloadedModuleTest extends DirectoryIndexTestCase { - public void testUnloadedModule() throws IOException { - Module unloadedModule = createModule("unloaded"); - final File root = createTempDirectory(); - VirtualFile contentRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(root); - ModuleRootModificationUtil.addContentRoot(unloadedModule, contentRoot.getPath()); - VirtualFile file = createChildData(contentRoot, "a.txt"); - assertInProject(file); - - ModuleManager.getInstance(myProject).setUnloadedModules(Arrays.asList("unloaded")); - - assertFromUnloadedModule(file, "unloaded"); - assertFromUnloadedModule(contentRoot, "unloaded"); +class DirectoryIndexForUnloadedModuleTest : DirectoryIndexTestCase() { + @Throws(IOException::class) + fun testUnloadedModule() { + val unloadedModule = createModule("unloaded") + val root = createTempDirectory() + val contentRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(root) + ModuleRootModificationUtil.addContentRoot(unloadedModule, contentRoot!!.path) + val file = HeavyPlatformTestCase.createChildData(contentRoot, "a.txt") + assertInProject(file) + runUnderModalProgressIfIsEdt { + getInstance(myProject).setUnloadedModules(Arrays.asList("unloaded")) + } + assertFromUnloadedModule(file, "unloaded") + assertFromUnloadedModule(contentRoot, "unloaded") } - public void testDependentUnloadedModules() { - Module unloadedModule = createModule("unloaded"); - Module main = createModule("main"); - Module util = createModule("util"); - Module common = createModule("common"); - ModuleRootModificationUtil.addDependency(unloadedModule, main); - ModuleRootModificationUtil.addDependency(main, util); - ModuleRootModificationUtil.addDependency(main, common, DependencyScope.COMPILE, true); - ModuleManager.getInstance(myProject).setUnloadedModules(Arrays.asList("unloaded")); - - assertSameElements(myIndex.getDependentUnloadedModules(main), "unloaded"); - assertEmpty(myIndex.getDependentUnloadedModules(util)); - assertSameElements(myIndex.getDependentUnloadedModules(common), "unloaded"); + fun testDependentUnloadedModules() { + val unloadedModule = createModule("unloaded") + val main = createModule("main") + val util = createModule("util") + val common = createModule("common") + ModuleRootModificationUtil.addDependency(unloadedModule, main) + ModuleRootModificationUtil.addDependency(main, util) + ModuleRootModificationUtil.addDependency(main, common, DependencyScope.COMPILE, true) + runUnderModalProgressIfIsEdt { + getInstance(myProject).setUnloadedModules(Arrays.asList("unloaded")) + } + UsefulTestCase.assertSameElements(myIndex.getDependentUnloadedModules(main), "unloaded") + UsefulTestCase.assertEmpty(myIndex.getDependentUnloadedModules(util)) + UsefulTestCase.assertSameElements(myIndex.getDependentUnloadedModules(common), "unloaded") } - private void assertFromUnloadedModule(VirtualFile file, String moduleName) { - DirectoryInfo info = myIndex.getInfoForFile(file); - assertTrue(info.toString(), info.isExcluded(file)); - assertNull(info.getModule()); - assertEquals(moduleName, info.getUnloadedModuleName()); + private fun assertFromUnloadedModule(file: VirtualFile?, moduleName: String) { + val info = myIndex.getInfoForFile(file!!) + assertTrue(info.toString(), info.isExcluded(file)) + assertNull(info.module) + assertEquals(moduleName, info.unloadedModuleName) } -} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java b/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java index db499b52bd90..9c02a6a00847 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/ui/configuration/actions/ModuleDeleteProviderTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.roots.ui.configuration.actions; import com.intellij.ide.projectView.ProjectView; @@ -15,7 +15,6 @@ import com.intellij.testFramework.HeavyPlatformTestCase; import com.intellij.testFramework.MapDataContext; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public class ModuleDeleteProviderTest extends HeavyPlatformTestCase { @@ -56,7 +55,7 @@ public class ModuleDeleteProviderTest extends HeavyPlatformTestCase { public void testUnloaded() { createModule("a"); - getModuleManager().setUnloadedModules(Arrays.asList("a")); + getModuleManager().setUnloadedModulesSync(List.of("a")); assertNotNull(getModuleManager().getUnloadedModuleDescription("a")); deleteModules("a"); assertNull(getModuleManager().getUnloadedModuleDescription("a")); @@ -66,7 +65,7 @@ public class ModuleDeleteProviderTest extends HeavyPlatformTestCase { Module a = createModule("a"); Module b = createModule("b"); ModuleRootModificationUtil.addDependency(a, b); - getModuleManager().setUnloadedModules(Arrays.asList("b")); + getModuleManager().setUnloadedModulesSync(List.of("b")); assertSameElements(ModuleRootManager.getInstance(a).getDependencyModuleNames(), "b"); deleteModules("b"); assertEmpty(ModuleRootManager.getInstance(a).getDependencyModuleNames()); @@ -78,7 +77,7 @@ public class ModuleDeleteProviderTest extends HeavyPlatformTestCase { ModuleRootModificationUtil.addDependency(a, b); ModuleRootModificationUtil.addDependency(myModule, a); ModuleRootModificationUtil.addDependency(myModule, b); - getModuleManager().setUnloadedModules(Arrays.asList("a")); + getModuleManager().setUnloadedModulesSync(List.of("a")); assertSameElements(ModuleRootManager.getInstance(myModule).getDependencyModuleNames(), "a", "b"); deleteModules("a", "b"); assertNull(getModuleManager().findModuleByName("a")); diff --git a/java/java-tests/testSrc/com/intellij/projectView/ModulesInProjectViewTest.kt b/java/java-tests/testSrc/com/intellij/projectView/ModulesInProjectViewTest.kt index 7baef4ffca48..8b78fa5c24c7 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/ModulesInProjectViewTest.kt +++ b/java/java-tests/testSrc/com/intellij/projectView/ModulesInProjectViewTest.kt @@ -1,7 +1,8 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.projectView import com.intellij.ide.highlighter.ModuleFileType +import com.intellij.ide.impl.runUnderModalProgressIfIsEdt import com.intellij.openapi.application.WriteAction import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager @@ -55,18 +56,20 @@ class ModulesInProjectViewTest : BaseProjectViewTestCase() { """.trimIndent() assertStructureEqual(expected) - ModuleManager.getInstance(myProject).setUnloadedModules(listOf("unloaded", "unloaded-inner")) + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(listOf("unloaded", "unloaded-inner")) + } assertStructureEqual(""" - Project - loaded - unloaded-inner - subdir - y.txt - unloaded - loaded-inner - subdir - z.txt - """.trimIndent()) + Project + loaded + unloaded-inner + subdir + y.txt + unloaded + loaded-inner + subdir + z.txt + """.trimIndent()) } fun `test unloaded module with qualified name`() { @@ -93,7 +96,9 @@ class ModulesInProjectViewTest : BaseProjectViewTestCase() { """.trimIndent() assertStructureEqual(expected) - ModuleManager.getInstance(myProject).setUnloadedModules(listOf("unloaded")) + runUnderModalProgressIfIsEdt { + ModuleManager.getInstance(myProject).setUnloadedModules(listOf("unloaded")) + } assertStructureEqual(expected) } diff --git a/java/java-tests/testSrc/com/intellij/roots/UnloadedModulesConfigurationTest.kt b/java/java-tests/testSrc/com/intellij/roots/UnloadedModulesConfigurationTest.kt index 1d6497678e9e..24c3bbcdb068 100644 --- a/java/java-tests/testSrc/com/intellij/roots/UnloadedModulesConfigurationTest.kt +++ b/java/java-tests/testSrc/com/intellij/roots/UnloadedModulesConfigurationTest.kt @@ -1,16 +1,15 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.roots import com.intellij.facet.FacetManager import com.intellij.facet.mock.MockFacetType import com.intellij.facet.mock.registerFacetType +import com.intellij.ide.impl.runUnderModalProgressIfIsEdt import com.intellij.idea.TestFor import com.intellij.openapi.application.ex.PathManagerEx import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.StdModuleTypes -import com.intellij.openapi.project.ex.ProjectManagerEx -import com.intellij.openapi.project.impl.ProjectManagerImpl import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.util.io.FileUtil @@ -46,12 +45,16 @@ class UnloadedModulesConfigurationTest : JavaModuleTestCase() { ModuleRootModificationUtil.addContentRoot(a, contentRootPath) ModuleRootModificationUtil.addDependency(a, b) val moduleManager = ModuleManager.getInstance(project) - moduleManager.setUnloadedModules(listOf("a")) + runUnderModalProgressIfIsEdt { + moduleManager.setUnloadedModules(listOf("a")) + } assertEquals("a", assertOneElement(moduleManager.unloadedModuleDescriptions).name) assertNull(moduleManager.findModuleByName("a")) assertNotNull(moduleManager.findModuleByName("b")) - moduleManager.setUnloadedModules(listOf("b")) + runUnderModalProgressIfIsEdt { + moduleManager.setUnloadedModules(listOf("b")) + } assertEquals("b", assertOneElement(moduleManager.unloadedModuleDescriptions).name) val newA = moduleManager.findModuleByName("a") assertNotNull(newA) @@ -73,12 +76,16 @@ class UnloadedModulesConfigurationTest : JavaModuleTestCase() { } val moduleManager = ModuleManager.getInstance(project) - moduleManager.setUnloadedModules(listOf("a")) + runUnderModalProgressIfIsEdt { + moduleManager.setUnloadedModules(listOf("a")) + } assertEquals("a", assertOneElement(moduleManager.unloadedModuleDescriptions).name) assertNull(moduleManager.findModuleByName("a")) assertNotNull(moduleManager.findModuleByName("b")) - moduleManager.setUnloadedModules(listOf()) + runUnderModalProgressIfIsEdt { + moduleManager.setUnloadedModules(listOf()) + } val moduleA = ModuleManager.getInstance(project).findModuleByName("a")!! val allFacets = FacetManager.getInstance(moduleA).allFacets @@ -92,7 +99,9 @@ class UnloadedModulesConfigurationTest : JavaModuleTestCase() { val a = createModule("a") val aImlPath = a.moduleFilePath val moduleManager = ModuleManager.getInstance(project) - moduleManager.setUnloadedModules(listOf("a")) + runUnderModalProgressIfIsEdt { + moduleManager.setUnloadedModules(listOf("a")) + } assertEquals("a", assertOneElement(moduleManager.unloadedModuleDescriptions).name) runWriteAction { @@ -105,16 +114,16 @@ class UnloadedModulesConfigurationTest : JavaModuleTestCase() { createModule("a") val b = createModule("b") val moduleManager = ModuleManager.getInstance(project) - moduleManager.setUnloadedModules(listOf("a")) + runUnderModalProgressIfIsEdt { + moduleManager.setUnloadedModules(listOf("a")) + } assertEquals("a", assertOneElement(moduleManager.unloadedModuleDescriptions).name) runWriteAction { - val model = moduleManager.modifiableModel + val model = moduleManager.getModifiableModel() model.renameModule(b, "a") model.commit() } assertEmpty(moduleManager.unloadedModuleDescriptions) } - - private fun getProjectManager() = ProjectManagerEx.getInstanceEx() as ProjectManagerImpl } \ No newline at end of file diff --git a/platform/core-impl/src/com/intellij/serviceContainer/PrecomputedExtensionModel.kt b/platform/core-impl/src/com/intellij/serviceContainer/PrecomputedExtensionModel.kt index ab0bc7701ce3..d8af28d7e82f 100644 --- a/platform/core-impl/src/com/intellij/serviceContainer/PrecomputedExtensionModel.kt +++ b/platform/core-impl/src/com/intellij/serviceContainer/PrecomputedExtensionModel.kt @@ -1,5 +1,5 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -@file:Suppress("ReplaceGetOrSet") +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +@file:Suppress("ReplaceGetOrSet", "ReplacePutWithAssignment") package com.intellij.serviceContainer import com.intellij.ide.plugins.IdeaPluginDescriptor diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt index b7ffd6865896..f09b3652cb5d 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt @@ -153,12 +153,14 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage }) project.messageBus.connect().subscribe(ProjectTopics.MODULES, object : ModuleListener { - override fun moduleAdded(project: Project, module: Module) { + override fun modulesAdded(project: Project, modules: List) { synchronized(mutex) { - moduleNamesToSourceFolderState[module.name].forEach { - loadSourceFolderState(it, module) + for (module in modules) { + moduleNamesToSourceFolderState[module.name].forEach { + loadSourceFolderState(it, module) + } + moduleNamesToSourceFolderState.remove(module.name) } - moduleNamesToSourceFolderState.remove(module.name) } } }) diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerTest.kt b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerTest.kt index 12cd0ff7b041..f8ae4808b2d7 100644 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerTest.kt +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.externalSystem.service.project.manage import com.intellij.openapi.application.runWriteAction @@ -103,7 +103,7 @@ class SourceFolderManagerTest: HeavyPlatformTestCase() { private fun createModuleWithContentRoot(dir: File, moduleName: String = "topModule"): Module { val moduleManager = ModuleManager.getInstance(project) - val modifiableModel = moduleManager.modifiableModel + val modifiableModel = moduleManager.getModifiableModel() val newModule: Module = try { modifiableModel.newModule(dir.toPath().resolve(moduleName).toAbsolutePath(), ModuleTypeId.JAVA_MODULE) diff --git a/platform/ide-core/resources/messages/ProjectBundle.properties b/platform/ide-core/resources/messages/ProjectBundle.properties index ab087cfaed8c..38c35dda5bdc 100644 --- a/platform/ide-core/resources/messages/ProjectBundle.properties +++ b/platform/ide-core/resources/messages/ProjectBundle.properties @@ -2,7 +2,6 @@ project.configuration.save.file.not.found={0} not found project.load.undefined.path.variables.message=There are undefined path variables in project configuration files. project.load.default.error=Error Loading Default Project project.loading.components=Loading components... -project.preparing.workspace=Preparing workspace... project.configure.path.variables.title=Configure Path Variables project.open.select.from.multiple.processors.dialog.title=Open or Import Project project.open.select.from.multiple.processors.dialog.description.line1=Found {0} project configurations in ''{1}''. diff --git a/platform/ide-core/src/com/intellij/openapi/project/ProjectUtil.kt b/platform/ide-core/src/com/intellij/openapi/project/ProjectUtil.kt index e53bbb3f5b31..0f0d5214ccae 100644 --- a/platform/ide-core/src/com/intellij/openapi/project/ProjectUtil.kt +++ b/platform/ide-core/src/com/intellij/openapi/project/ProjectUtil.kt @@ -105,7 +105,7 @@ val Project.modules: Array get() = ModuleManager.getInstance(this).modules inline fun Project.modifyModules(crossinline task: ModifiableModuleModel.() -> T): T { - val model = ModuleManager.getInstance(this).modifiableModel + val model = ModuleManager.getInstance(this).getModifiableModel() val result = model.task() runWriteAction { model.commit() diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetEventsPublisher.kt b/platform/lang-impl/src/com/intellij/facet/impl/FacetEventsPublisher.kt index dbbaaae6808a..1b6cc360c63d 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/FacetEventsPublisher.kt +++ b/platform/lang-impl/src/com/intellij/facet/impl/FacetEventsPublisher.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.facet.impl import com.intellij.ProjectTopics @@ -13,7 +13,6 @@ import com.intellij.openapi.project.ModuleListener import com.intellij.openapi.project.Project import com.intellij.util.containers.ContainerUtil import java.util.* -import kotlin.collections.HashMap @Service internal class FacetEventsPublisher(private val project: Project) { @@ -23,8 +22,10 @@ internal class FacetEventsPublisher(private val project: Project) { init { val connection = project.messageBus.connect() connection.subscribe(ProjectTopics.MODULES, object : ModuleListener { - override fun moduleAdded(project: Project, module: Module) { - onModuleAdded(module) + override fun modulesAdded(project: Project, modules: MutableList) { + for (module in modules) { + onModuleAdded(module) + } } override fun moduleRemoved(project: Project, module: Module) { diff --git a/platform/lang-impl/src/com/intellij/facet/impl/ProjectFacetManagerImpl.java b/platform/lang-impl/src/com/intellij/facet/impl/ProjectFacetManagerImpl.java index 8f63dfb24efc..4219d95fdaf6 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/ProjectFacetManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/facet/impl/ProjectFacetManagerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.facet.impl; import com.intellij.ProjectTopics; @@ -46,7 +46,7 @@ public final class ProjectFacetManagerImpl extends ProjectFacetManagerEx impleme }, project); project.getMessageBus().connect().subscribe(ProjectTopics.MODULES, new ModuleListener() { @Override - public void moduleAdded(@NotNull Project project, @NotNull Module module) { + public void modulesAdded(@NotNull Project project, @NotNull List modules) { myIndex = null; } diff --git a/platform/lang-impl/src/com/intellij/facet/impl/pointers/FacetPointerModuleListener.java b/platform/lang-impl/src/com/intellij/facet/impl/pointers/FacetPointerModuleListener.java index b3d88fd7a25d..a23bd3de6b93 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/pointers/FacetPointerModuleListener.java +++ b/platform/lang-impl/src/com/intellij/facet/impl/pointers/FacetPointerModuleListener.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.facet.impl.pointers; import com.intellij.facet.pointers.FacetPointersManager; @@ -10,18 +10,18 @@ import org.jetbrains.annotations.NotNull; import java.util.List; -public class FacetPointerModuleListener implements ModuleListener { - +final class FacetPointerModuleListener implements ModuleListener { private final Project myProject; - public FacetPointerModuleListener(Project project) { myProject = project; } + FacetPointerModuleListener(Project project) { + myProject = project; + } @Override - public void moduleAdded(@NotNull Project project, @NotNull Module module) { + public void modulesAdded(@NotNull Project project, @NotNull List modules) { FacetPointersManager manager = FacetPointersManager.getInstance(myProject); if (manager instanceof FacetPointersManagerImpl) { - FacetPointersManagerImpl managerImpl = (FacetPointersManagerImpl)manager; - managerImpl.refreshPointers(); + ((FacetPointersManagerImpl)manager).refreshPointers(); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/AutomaticModuleUnloaderImpl.kt b/platform/lang-impl/src/com/intellij/openapi/module/impl/AutomaticModuleUnloaderImpl.kt index ee1c442cf371..8ee7bc6bb256 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/AutomaticModuleUnloaderImpl.kt +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/AutomaticModuleUnloaderImpl.kt @@ -18,6 +18,7 @@ import com.intellij.workspaceModel.storage.EntityStorage import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleDependencyItem import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleId import com.intellij.xml.util.XmlStringUtil +import kotlinx.coroutines.launch /** * If some modules were unloaded and new modules appears after loading project configuration, automatically unloads those which @@ -119,7 +120,9 @@ internal class AutomaticModuleUnloaderImpl(private val project: Project) : Simpl val moduleManager = ModuleManager.getInstance(project) moduleManager.unloadedModuleDescriptions.mapTo(unloaded) { it.name } action(unloaded) - moduleManager.setUnloadedModules(unloaded) + project.coroutineScope.launch { + moduleManager.setUnloadedModules(unloaded) + } notification.expire() } } diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java index 4dc1f11e3e64..5a57dc8c4263 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java @@ -11,7 +11,6 @@ import com.intellij.openapi.components.impl.stores.IComponentStore; import com.intellij.openapi.components.impl.stores.ModuleStore; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleComponent; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.impl.scopes.ModuleScopeProviderImpl; import com.intellij.openapi.progress.ProgressIndicator; @@ -197,10 +196,10 @@ public class ModuleImpl extends ComponentManagerImpl implements ModuleEx { @Override public void projectOpened() { - //noinspection deprecation - processInitializedComponents(ModuleComponent.class, (component, __) -> { + //noinspection removal,UnnecessaryFullyQualifiedName + processInitializedComponents(com.intellij.openapi.module.ModuleComponent.class, (component, __) -> { try { - //noinspection deprecation + //noinspection removal component.projectOpened(); } catch (Exception e) { @@ -212,17 +211,17 @@ public class ModuleImpl extends ComponentManagerImpl implements ModuleEx { @Override public void projectClosed() { - //noinspection deprecation - List components = new ArrayList<>(); - //noinspection deprecation - processInitializedComponents(ModuleComponent.class, (component, __) -> { + @SuppressWarnings({"removal", "UnnecessaryFullyQualifiedName"}) + List components = new ArrayList<>(); + //noinspection removal,UnnecessaryFullyQualifiedName + processInitializedComponents(com.intellij.openapi.module.ModuleComponent.class, (component, __) -> { components.add(component); return Unit.INSTANCE; }); for (int i = components.size() - 1; i >= 0; i--) { try { - //noinspection deprecation + //noinspection removal components.get(i).projectClosed(); } catch (Throwable e) { @@ -251,9 +250,9 @@ public class ModuleImpl extends ComponentManagerImpl implements ModuleEx { @Override public void moduleAdded() { isModuleAdded = true; - //noinspection deprecation - processInitializedComponents(ModuleComponent.class, (component, __) -> { - //noinspection deprecation + //noinspection removal,UnnecessaryFullyQualifiedName + processInitializedComponents(com.intellij.openapi.module.ModuleComponent.class, (component, __) -> { + //noinspection removal component.moduleAdded(); return Unit.INSTANCE; }); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java index 0c057d062a90..6a6dfee14485 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java @@ -67,6 +67,8 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen private final static ExtensionPointName WATCHED_ROOTS_PROVIDER_EP_NAME = new ExtensionPointName<>("com.intellij.roots.watchedRootsProvider"); + private boolean isStartupActivityPerformed; + private final ExecutorService myExecutor = ApplicationManager.getApplication().isUnitTestMode() ? ConcurrencyUtil.newSameThreadExecutorService() : AppExecutorUtil.createBoundedApplicationPoolExecutor("Project Root Manager", 1); @@ -119,7 +121,7 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen } }); - StartupManager.getInstance(myProject).registerStartupActivity(() -> myStartupActivityPerformed = true); + StartupManager.getInstance(myProject).registerStartupActivity(() -> isStartupActivityPerformed = true); connection.subscribe(BatchUpdateListener.TOPIC, new BatchUpdateListener() { @Override @@ -209,7 +211,9 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen isFiringEvent = false; } - synchronizeRoots(indexingInfos); + if (isStartupActivityPerformed) { + EntityIndexingService.getInstance().indexChanges(myProject, indexingInfos); + } addRootsToWatch(); } @@ -294,11 +298,6 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen } } - private void synchronizeRoots(@NotNull List indexingInfos) { - if (!myStartupActivityPerformed) return; - EntityIndexingService.getInstance().indexChanges(myProject, indexingInfos); - } - @Override protected void clearScopesCaches() { super.clearScopesCaches(); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ConfigureUnloadedModulesDialog.kt b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ConfigureUnloadedModulesDialog.kt index b1c746225bd9..8b932b8a8ade 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ConfigureUnloadedModulesDialog.kt +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ConfigureUnloadedModulesDialog.kt @@ -30,6 +30,7 @@ import com.intellij.util.graph.* import com.intellij.util.ui.GridBag import com.intellij.util.ui.tree.TreeUtil import com.intellij.xml.util.XmlStringUtil +import kotlinx.coroutines.launch import java.awt.BorderLayout import java.awt.Dimension import java.awt.GridBagConstraints @@ -198,7 +199,10 @@ class ConfigureUnloadedModulesDialog(private val project: Project, selectedModul } override fun doOKAction() { - ModuleManager.getInstance(project).setUnloadedModules(unloadedModulesTree.getAllModules().map { it.name }) + val unloadedModuleNames = unloadedModulesTree.getAllModules().map { it.name } + project.coroutineScope.launch { + ModuleManager.getInstance(project).setUnloadedModules(unloadedModuleNames) + } super.doOKAction() } } diff --git a/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeImpl.kt b/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeImpl.kt index f9cc5ed294ec..ab08c32ebf54 100644 --- a/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeImpl.kt +++ b/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeImpl.kt @@ -1,7 +1,8 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.workspaceModel.ide.impl.legacyBridge.module import com.intellij.configurationStore.RenameableStateStorageManager +import com.intellij.facet.Facet import com.intellij.facet.FacetManager import com.intellij.ide.plugins.IdeaPluginDescriptor import com.intellij.ide.plugins.IdeaPluginDescriptorImpl @@ -23,16 +24,17 @@ import com.intellij.workspaceModel.ide.impl.legacyBridge.module.ModuleManagerBri import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge import com.intellij.workspaceModel.ide.toPath import com.intellij.workspaceModel.storage.EntityChange +import com.intellij.workspaceModel.storage.MutableEntityStorage import com.intellij.workspaceModel.storage.VersionedEntityStorage import com.intellij.workspaceModel.storage.VersionedStorageChange -import com.intellij.workspaceModel.storage.MutableEntityStorage import com.intellij.workspaceModel.storage.bridgeEntities.addModuleCustomImlDataEntity import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleEntity import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleId +import com.intellij.workspaceModel.storage.bridgeEntities.api.modifyEntity import com.intellij.workspaceModel.storage.impl.VersionedEntityStorageOnStorage import com.intellij.workspaceModel.storage.url.VirtualFileUrl -import com.intellij.workspaceModel.storage.bridgeEntities.api.modifyEntity +@Suppress("OVERRIDE_DEPRECATION") internal class ModuleBridgeImpl( override var moduleEntityId: ModuleId, name: String, @@ -97,7 +99,7 @@ internal class ModuleBridgeImpl( } override fun initFacets() { - FacetManager.getInstance(this).allFacets.forEach { it.initFacet() } + FacetManager.getInstance(this).allFacets.forEach(Facet<*>::initFacet) } override fun registerComponents(corePlugin: IdeaPluginDescriptor?, @@ -163,6 +165,7 @@ internal class ModuleBridgeImpl( } } else { + @Suppress("DEPRECATION") if (getOptionValue(key) != value) { WriteAction.runAndWait { WorkspaceModel.getInstance(project).updateProjectModel { builder -> @@ -177,6 +180,4 @@ internal class ModuleBridgeImpl( return } - - override fun getOptionsModificationCount(): Long = 0 } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeLoaderService.kt b/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeLoaderService.kt index 3ae3a9acb1cf..174cbf0b1483 100644 --- a/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeLoaderService.kt +++ b/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleBridgeLoaderService.kt @@ -24,37 +24,52 @@ import com.intellij.workspaceModel.ide.impl.legacyBridge.project.ProjectRootMana import com.intellij.workspaceModel.storage.EntitySource import com.intellij.workspaceModel.storage.EntityStorage import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleEntity -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* internal class ModuleBridgeLoaderService(private val project: Project) { + companion object { + private val LOG = logger() + } + private var storeToEntitySources: Pair>? = null private var activity: Activity? = null + private val loadModuleJob: Job + init { - if (!project.isDefault) { - val workspaceModel = WorkspaceModel.getInstance(project) as WorkspaceModelImpl + if (project.isDefault) { + loadModuleJob = CompletableDeferred(value = null) + } + else { val projectModelSynchronizer = JpsProjectModelSynchronizer.getInstance(project) - if (projectModelSynchronizer != null) { - if (workspaceModel.loadedFromCache && projectModelSynchronizer.hasNoSerializedJpsModules()) { - LOG.warn("Loaded from cache, but no serialized modules found. Workspace model cache will be ignored, project structure will be recreated.") - workspaceModel.ignoreCache() // sets `WorkspaceModelImpl#loadedFromCache` to `false` - project.putUserData(PROJECT_LOADED_FROM_CACHE_BUT_HAS_NO_MODULES, true) + if (projectModelSynchronizer == null) { + loadModuleJob = CompletableDeferred(value = null) + } + else { + val workspaceModel = WorkspaceModel.getInstance(project) as WorkspaceModelImpl + if (workspaceModel.loadedFromCache) { + if (projectModelSynchronizer.hasNoSerializedJpsModules()) { + LOG.warn("Loaded from cache, but no serialized modules found. Workspace model cache will be ignored, project structure will be recreated.") + workspaceModel.ignoreCache() // sets `WorkspaceModelImpl#loadedFromCache` to `false` + project.putUserData(PROJECT_LOADED_FROM_CACHE_BUT_HAS_NO_MODULES, true) + } + + activity = StartUpMeasurer.startActivity("modules loading with cache", ActivityCategory.DEFAULT) + loadModuleJob = project.coroutineScope.async { + loadModules() + } } - if (!workspaceModel.loadedFromCache) { + else { LOG.info("Workspace model loaded without cache. Loading real project state into workspace model. ${Thread.currentThread()}") activity = StartUpMeasurer.startActivity("modules loading without cache", ActivityCategory.DEFAULT) storeToEntitySources = projectModelSynchronizer.loadProjectToEmptyStorage(project) - } - else { - activity = StartUpMeasurer.startActivity("modules loading with cache", ActivityCategory.DEFAULT) - loadModules() + loadModuleJob = CompletableDeferred(value = null) } } } } - private fun loadModules() { + private suspend fun loadModules() { val childActivity = activity?.startChild("modules instantiation") val moduleManager = ModuleManager.getInstance(project) as ModuleManagerComponentBridge val entities = moduleManager.entityStore.current.entities(ModuleEntity::class.java) @@ -72,8 +87,11 @@ internal class ModuleBridgeLoaderService(private val project: Project) { override suspend fun serviceCreated(project: Project) { LOG.debug { "Project component initialized" } val workspaceModel = WorkspaceModel.getInstance(project) as WorkspaceModelImpl + + val moduleLoaderService = project.getService(ModuleBridgeLoaderService::class.java) + moduleLoaderService.loadModuleJob.join() + if (!workspaceModel.loadedFromCache) { - val moduleLoaderService = project.getService(ModuleBridgeLoaderService::class.java) val projectModelSynchronizer = JpsProjectModelSynchronizer.getInstance(project) ?: return projectModelSynchronizer.applyLoadedStorage(moduleLoaderService.storeToEntitySources) project.messageBus.syncPublisher(JpsProjectLoadedListener.LOADED).loaded() @@ -88,13 +106,5 @@ internal class ModuleBridgeLoaderService(private val project: Project) { } WorkspaceModelTopics.getInstance(project).notifyModulesAreLoaded() } - - companion object { - private val LOG = logger() - } - } - - companion object { - private val LOG = logger() } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerComponentBridge.kt b/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerComponentBridge.kt index c4cb2beaad29..94f5372fb86c 100644 --- a/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerComponentBridge.kt +++ b/platform/lang-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerComponentBridge.kt @@ -1,22 +1,25 @@ -// Copyright 2000-2021 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.workspaceModel.ide.impl.legacyBridge.module import com.intellij.ProjectTopics import com.intellij.diagnostic.ActivityCategory import com.intellij.diagnostic.StartUpMeasurer import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.EDT import com.intellij.openapi.components.ServiceDescriptor import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.module.AutomaticModuleUnloader import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.impl.ModuleEx import com.intellij.openapi.module.impl.NonPersistentModuleStore import com.intellij.openapi.module.impl.UnloadedModulesListStorage import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.ProjectManagerListener +import com.intellij.openapi.startup.InitProjectActivity import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.serviceContainer.ComponentManagerImpl @@ -32,32 +35,50 @@ import com.intellij.workspaceModel.ide.impl.legacyBridge.module.roots.ModuleRoot import com.intellij.workspaceModel.ide.impl.legacyBridge.project.ProjectRootsChangeListener import com.intellij.workspaceModel.ide.impl.legacyBridge.watcher.VirtualFileUrlWatcher import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge -import com.intellij.workspaceModel.storage.* +import com.intellij.workspaceModel.storage.EntityChange +import com.intellij.workspaceModel.storage.MutableEntityStorage +import com.intellij.workspaceModel.storage.VersionedEntityStorage +import com.intellij.workspaceModel.storage.VersionedStorageChange import com.intellij.workspaceModel.storage.bridgeEntities.api.* import com.intellij.workspaceModel.storage.url.VirtualFileUrl import com.intellij.workspaceModel.storage.url.VirtualFileUrlManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.IOException import java.nio.file.Paths class ModuleManagerComponentBridge(private val project: Project) : ModuleManagerBridgeImpl(project) { private val virtualFileManager: VirtualFileUrlManager = VirtualFileUrlManager.getInstance(project) + internal class ModuleManagerInitProjectActivity : InitProjectActivity { + override suspend fun run(project: Project) { + val activity = StartUpMeasurer.startActivity("firing modules_added event", ActivityCategory.DEFAULT) + val moduleManager = ModuleManager.getInstance(project) as ModuleManagerComponentBridge + val modules = moduleManager.modules().toList() + withContext(Dispatchers.EDT) { + ApplicationManager.getApplication().runWriteAction { + for (module in modules) { + if (!module.isLoaded) { + module.moduleAdded() + } + } + } + + moduleManager.fireModulesAdded(modules) + + for (module in modules) { + module.projectOpened() + } + } + activity.end() + } + } + init { // default project doesn't have modules if (!project.isDefault) { val busConnection = project.messageBus.connect(this) busConnection.subscribe(ProjectManager.TOPIC, object : ProjectManagerListener { - override fun projectOpened(eventProject: Project) { - val activity = StartUpMeasurer.startActivity("firing modules_added event", ActivityCategory.DEFAULT) - if (project == eventProject) { - fireModulesAdded() - for (module in modules()) { - module.projectOpened() - } - } - activity.end() - } - override fun projectClosed(eventProject: Project) { if (project == eventProject) { for (module in modules()) { @@ -172,7 +193,7 @@ class ModuleManagerComponentBridge(private val project: Project) : ModuleManager oldModuleNames: MutableMap, event: VersionedStorageChange) { when (change) { is EntityChange.Removed -> { - // It's possible case then idToModule doesn't contain element e.g if unloaded module was removed + // It's possible case then idToModule doesn't contain element e.g. if unloaded module was removed val module = event.storageBefore.findModuleByEntity(change.entity) if (module != null) { fireEventAndDisposeModule(module) @@ -271,23 +292,17 @@ class ModuleManagerComponentBridge(private val project: Project) : ModuleManager private fun List>.filterModuleLibraryChanges() = filter { it.isModuleLibrary() } - private fun fireModulesAdded() { - for (module in modules()) { - fireModuleAddedInWriteAction(module) - } - } - private fun fireModuleAddedInWriteAction(module: ModuleEx) { ApplicationManager.getApplication().runWriteAction { if (!module.isLoaded) { module.moduleAdded() - fireModuleAdded(module) + fireModulesAdded(listOf(module)) } } } - private fun fireModuleAdded(module: Module) { - project.messageBus.syncPublisher(ProjectTopics.MODULES).moduleAdded(project, module) + private fun fireModulesAdded(modules: List) { + project.messageBus.syncPublisher(ProjectTopics.MODULES).modulesAdded(project, modules) } override fun registerNonPersistentModuleStore(module: ModuleBridge) { diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt index 72e7df5e608d..698cda1de341 100644 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleDependencyInRootModelTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.roots import com.intellij.openapi.application.runReadAction @@ -260,7 +260,7 @@ class ModuleDependencyInRootModelTest { val a = projectModel.createModule("a") val model = createModifiableModel(mainModule) model.addModuleOrderEntry(a) - val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val moduleModel = runReadAction { projectModel.moduleManager.getModifiableModel() } moduleModel.renameModule(a, "b") val entry = dropModuleSourceEntry(model, 1).single() as ModuleOrderEntry assertThat(entry.module).isEqualTo(a) @@ -300,7 +300,7 @@ class ModuleDependencyInRootModelTest { @Test fun `add not yet committed module`() { - val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val moduleModel = runReadAction { projectModel.moduleManager.getModifiableModel() } val a = projectModel.createModule("a", moduleModel) run { val model = createModifiableModel(mainModule) @@ -319,7 +319,7 @@ class ModuleDependencyInRootModelTest { @Test fun `add not yet committed module and do not commit it`() { - val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val moduleModel = runReadAction { projectModel.moduleManager.getModifiableModel() } val a = projectModel.createModule("a", moduleModel) run { val model = createModifiableModel(mainModule) @@ -339,7 +339,7 @@ class ModuleDependencyInRootModelTest { @Test fun `add not yet committed module with configuration accessor`() { - val moduleModel = runReadAction { projectModel.moduleManager.modifiableModel } + val moduleModel = runReadAction { projectModel.moduleManager.getModifiableModel() } val a = projectModel.createModule("a", moduleModel) run { val model = createModifiableModel(mainModule, object : RootConfigurationAccessor() { diff --git a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleModelTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleModelTest.kt index 986b4f6c4ea1..a2d22dd63b89 100644 --- a/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleModelTest.kt +++ b/platform/lang-impl/testSources/com/intellij/openapi/roots/ModuleModelTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.roots import com.intellij.openapi.application.runReadAction @@ -306,7 +306,7 @@ class ModuleModelTest { assertThat(modules[0].name).isEqualTo(antModuleName) runWriteActionAndWait { - moduleManager.modifiableModel.let { model -> + moduleManager.getModifiableModel().let { model -> model.renameModule(antModule, mavenModuleName) model.renameModule(antModule, gradleModuleName) model.commit() @@ -373,7 +373,7 @@ class ModuleModelTest { private fun createModifiableModuleModel(): @NotNull ModifiableModuleModel { //we need to get module manager outside of read action because it may lazily initialize the project requiring write action val moduleManager = projectModel.moduleManager - return runReadAction { moduleManager.modifiableModel } + return runReadAction { moduleManager.getModifiableModel() } } private fun getSortedModules() = runReadAction { projectModel.moduleManager.sortedModules } diff --git a/platform/platform-api/resources/messages/IdeBundle.properties b/platform/platform-api/resources/messages/IdeBundle.properties index 17ebd7a78175..6dacb38575e7 100644 --- a/platform/platform-api/resources/messages/IdeBundle.properties +++ b/platform/platform-api/resources/messages/IdeBundle.properties @@ -1849,7 +1849,6 @@ notification.group.system.messages=System messages action.text.install.keymap=Install {0} Keymap action.text.search.for.keymap=Search for {0} Keymap plugin action.separator.file.templates=File templates -startup.indicator.text.running.startup.activities=Running startup activities\u2026 notification.configurable.display.name.notifications=Notifications dumb.balloon.this.action=This action dumb.balloon.none.of.the.following.actions=None of the following actions diff --git a/platform/platform-impl/src/com/intellij/ide/RecentProjectMetaInfo.kt b/platform/platform-impl/src/com/intellij/ide/RecentProjectMetaInfo.kt index 1fa8e0bd8b70..323a69d2ecf7 100644 --- a/platform/platform-impl/src/com/intellij/ide/RecentProjectMetaInfo.kt +++ b/platform/platform-impl/src/com/intellij/ide/RecentProjectMetaInfo.kt @@ -1,4 +1,6 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +@file:Suppress("ReplaceGetOrSet") + package com.intellij.ide import com.intellij.openapi.components.BaseState @@ -60,7 +62,7 @@ class RecentProjectManagerState : BaseState() { fun validateRecentProjects(modCounter: AtomicLong) { val limit = AdvancedSettings.getInt("ide.max.recent.projects") - if (additionalInfo.size <= limit) { + if (additionalInfo.size <= limit || limit < 1) { return } @@ -68,7 +70,7 @@ class RecentProjectManagerState : BaseState() { val iterator = additionalInfo.keys.iterator() while (iterator.hasNext()) { val path = iterator.next() - if (!additionalInfo[path]!!.opened) { + if (!additionalInfo.get(path)!!.opened) { iterator.remove() break } diff --git a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt index 14581fc2c064..a52712332888 100644 --- a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt +++ b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt @@ -21,10 +21,12 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx import com.intellij.openapi.components.* import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.runAndLogException +import com.intellij.openapi.extensions.ExtensionNotApplicableException import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManagerListener import com.intellij.openapi.project.ex.ProjectManagerEx import com.intellij.openapi.project.impl.* +import com.intellij.openapi.startup.ProjectPostStartupActivity import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil @@ -317,10 +319,6 @@ open class RecentProjectsManagerBase : RecentProjectsManager, PersistentStateCom } } - fun setLastOpenedProject(path: String) { - state.lastOpenedProject = path - } - fun getLastOpenedProject() = state.lastOpenedProject init { @@ -336,28 +334,42 @@ open class RecentProjectsManagerBase : RecentProjectsManager, PersistentStateCom }, AWTEvent.WINDOW_EVENT_MASK) } + @VisibleForTesting + suspend fun runProjectPostStartupActivity(project: Project) { + if (disableUpdatingRecentInfo.get() || LightEdit.owns(project)) { + return + } + + val projectPath = getProjectPath(project) ?: return + synchronized(stateLock) { + findAndRemoveNewlyClonedProject(projectPath) + markPathRecent(projectPath, project) + state.lastOpenedProject = projectPath + + updateProjectOpenedState(project, updateTime = true) + state.validateRecentProjects(modCounter) + } + + withContext(Dispatchers.EDT) { + updateSystemDockMenu() + } + } + + internal class MyProjectPostStartupActivity : ProjectPostStartupActivity { + init { + if (ApplicationManager.getApplication().isUnitTestMode) { + throw ExtensionNotApplicableException.create() + } + } + + override suspend fun execute(project: Project) { + getInstanceEx().runProjectPostStartupActivity(project) + } + } + @Internal @VisibleForTesting class MyProjectListener : ProjectManagerListener { - override fun projectOpened(project: Project) { - val manager = getInstanceEx() - if (manager.disableUpdatingRecentInfo.get() || LightEdit.owns(project)) { - return - } - - manager.getProjectPath(project)?.let { path -> - synchronized(manager.stateLock) { - manager.findAndRemoveNewlyClonedProject(path) - manager.markPathRecent(path, project) - manager.setLastOpenedProject(path) - - manager.updateProjectOpenedState(project, updateTime = true) - manager.state.validateRecentProjects(manager.modCounter) - } - } - updateSystemDockMenu() - } - override fun projectClosing(project: Project) { val app = ApplicationManagerEx.getApplicationEx() if (app.isExitInProgress) { @@ -385,7 +397,7 @@ open class RecentProjectsManagerBase : RecentProjectsManager, PersistentStateCom fun getRecentPaths(): List { synchronized(stateLock) { state.validateRecentProjects(modCounter) - return state.additionalInfo.keys.toList().asReversed() + return state.additionalInfo.keys.reversed() } } diff --git a/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java b/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java deleted file mode 100644 index 3419a0507888..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java +++ /dev/null @@ -1,173 +0,0 @@ -// 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.ide; - -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.project.ProjectManagerListener; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.openapi.wm.StatusBar; -import com.intellij.openapi.wm.impl.ProjectFrameHelper; -import com.intellij.util.Alarm; -import com.intellij.util.BitUtil; -import com.intellij.util.ReflectionUtil; -import org.jetbrains.annotations.NotNull; - -import javax.accessibility.Accessible; -import javax.accessibility.AccessibleContext; -import javax.swing.*; -import javax.swing.event.CaretListener; -import javax.swing.event.ChangeListener; -import javax.swing.event.DocumentListener; -import javax.swing.text.AbstractDocument; -import javax.swing.text.Document; -import javax.swing.text.JTextComponent; -import java.awt.*; -import java.awt.event.HierarchyEvent; -import java.lang.reflect.Field; -import java.util.EventListener; - -/** - * This class listens event from ProjectManager and cleanup some - * internal Swing references. - * - * @author Vladimir Kondratyev - */ -public final class SwingCleanuper { - private final Alarm myAlarm; - - public SwingCleanuper(@NotNull Application application) { - myAlarm = new Alarm(application); - application.getMessageBus().connect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() { - @Override - public void projectOpened(@NotNull final Project project) { - myAlarm.cancelAllRequests(); - } - // Swing keeps references to the last focused component inside DefaultKeyboardFocusManager.realOppositeComponent - // which is used to compose next focus event. Actually this component could be an editors or a tool window. To fix this - // memory leak we (if the project was closed and a new one was not opened yet) request focus to the status bar and after - // the focus events have passed the queue, we put 'null' to the DefaultKeyboardFocusManager.realOppositeComponent field. - @Override - public void projectClosed(@NotNull final Project project){ - myAlarm.cancelAllRequests(); - myAlarm.addRequest( - () -> { - // request focus into some focusable component inside IdeFrame - ProjectFrameHelper frame = ProjectFrameHelper.getFrameHelper(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow()); - if (frame != null) { - final Application app = ApplicationManager.getApplication(); - if (app != null && app.isActive()) { - StatusBar statusBar = frame.getStatusBar(); - if (statusBar != null) { - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus((JComponent)statusBar, true)); - } - } - } - }, - 2500 - ); - } - } - ); - - if (SystemInfo.isMac) { - Toolkit.getDefaultToolkit().addAWTEventListener(event -> { - if (!Registry.is("ide.mac.fix.accessibleLeak")) return; - - HierarchyEvent he = (HierarchyEvent)event; - if (BitUtil.isSet(he.getChangeFlags(), HierarchyEvent.SHOWING_CHANGED)) { - if (he.getComponent() != null && !he.getComponent().isShowing()) { - Component c = he.getComponent(); - if (c instanceof JTextComponent) { - JTextComponent textComponent = (JTextComponent)c; - - CaretListener[] carets = textComponent.getListeners(CaretListener.class); - for (CaretListener each : carets) { - if (isCAccessibleListener(each)) { - textComponent.removeCaretListener(each); - } - } - - Document document = textComponent.getDocument(); - if (document instanceof AbstractDocument) { - DocumentListener[] documentListeners = ((AbstractDocument)document).getDocumentListeners(); - for (DocumentListener each : documentListeners) { - if (isCAccessibleListener(each)) { - document.removeDocumentListener(each); - } - } - } - } - else if (c instanceof JProgressBar) { - JProgressBar bar = (JProgressBar)c; - ChangeListener[] changeListeners = bar.getChangeListeners(); - for (ChangeListener each : changeListeners) { - if (isCAccessibleListener(each)) { - bar.removeChangeListener(each); - } - } - } - else if (c instanceof JSlider) { - JSlider slider = (JSlider)c; - ChangeListener[] changeListeners = slider.getChangeListeners(); - for (ChangeListener each : changeListeners) { - if (isCAccessibleListener(each)) { - slider.removeChangeListener(each); - } - } - } - - Field nativeAXResource_Field = null; - Field accessibleContext_Field = null; - try { - nativeAXResource_Field = ReflectionUtil.findField(AccessibleContext.class, Object.class, "nativeAXResource"); - accessibleContext_Field = ReflectionUtil.findField(Component.class, AccessibleContext.class, "accessibleContext"); - } - catch (NoSuchFieldException ignored) { - } - - if (accessibleContext_Field != null) { - try { - // Component's AccessibleContext is not necessarily initialized. In this case we don't want to force its creation. - // So, first we check the Component.accessibleContext field. The field has a protected access and it's a common - // Swing pattern to set it in the Component.getAccessibleContext() method when it's overriden by a subclass - // (and we're to follow it). - AccessibleContext ac = (AccessibleContext)accessibleContext_Field.get(c); - if (ac != null) { - // The getter may have a side effect, so call it to get the up-to-date context. - ac = c.getAccessibleContext(); - if (ac != null) { - Object resource = nativeAXResource_Field.get(ac); - if (resource != null && isCAccessible(resource)) { - Field accessible = ReflectionUtil.findField(resource.getClass(), Accessible.class, "accessible"); - accessible.set(resource, null); - } - } - } - } - catch (Exception ignored) { - } - } - } - } - }, AWTEvent.HIERARCHY_EVENT_MASK); - } - } - - private static boolean isCAccessible(Object resource) { - final String name = resource.getClass().getName(); - return isCAccessible(name); - } - - static boolean isCAccessible(String name) { - return name.equals("apple.awt.CAccessible") || name.equals("sun.lwawt.macosx.CAccessible"); - } - - private static boolean isCAccessibleListener(EventListener listener) { - return listener != null && listener.toString().contains("AXTextChangeNotifier"); - } - -} diff --git a/platform/platform-impl/src/com/intellij/ide/actions/project/convertModuleGroupsToQualifiedNames.kt b/platform/platform-impl/src/com/intellij/ide/actions/project/convertModuleGroupsToQualifiedNames.kt index 9c65bfce29ec..2617a80c86c8 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/project/convertModuleGroupsToQualifiedNames.kt +++ b/platform/platform-impl/src/com/intellij/ide/actions/project/convertModuleGroupsToQualifiedNames.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.actions.project import com.intellij.CommonBundle @@ -174,7 +174,7 @@ internal class ConvertModuleGroupsToQualifiedNamesDialog(val project: Project) : val renamingScheme = getRenamingScheme() if (renamingScheme.isNotEmpty()) { - val model = ModuleManager.getInstance(project).modifiableModel + val model = ModuleManager.getInstance(project).getModifiableModel() val byName = modules.associateBy { it.name } for (entry in renamingScheme) { model.renameModule(byName[entry.key]!!, entry.value) diff --git a/platform/platform-impl/src/com/intellij/ide/lightEdit/project/LightEditProjectManager.kt b/platform/platform-impl/src/com/intellij/ide/lightEdit/project/LightEditProjectManager.kt index fac48d31375c..e8ed327aa50d 100644 --- a/platform/platform-impl/src/com/intellij/ide/lightEdit/project/LightEditProjectManager.kt +++ b/platform/platform-impl/src/com/intellij/ide/lightEdit/project/LightEditProjectManager.kt @@ -1,88 +1,79 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.ide.lightEdit.project; +package com.intellij.ide.lightEdit.project -import com.intellij.ide.startup.impl.StartupManagerImpl; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.project.ProjectManagerListener; -import com.intellij.openapi.startup.StartupManager; -import com.intellij.util.TimeoutUtil; -import kotlin.coroutines.EmptyCoroutineContext; -import kotlinx.coroutines.BuildersKt; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.ide.impl.runUnderModalProgressIfIsEdt +import com.intellij.ide.startup.impl.StartupManagerImpl +import com.intellij.openapi.actionSystem.ActionManager +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.project.ProjectManagerListener +import com.intellij.openapi.startup.StartupManager +import com.intellij.util.TimeoutUtil -public final class LightEditProjectManager { - private static final Logger LOG = Logger.getInstance(LightEditProjectManager.class); - private static final Object LOCK = new Object(); +class LightEditProjectManager { + companion object { + private val LOG = logger() + private val LOCK = Any() - private volatile LightEditProjectImpl myProject; + private fun fireProjectOpened(project: Project) { + val app = ApplicationManager.getApplication() + val fireRunnable = Runnable { + // similar to com.intellij.openapi.project.impl.ProjectManagerExImplKt.openProject + app.messageBus.syncPublisher(ProjectManager.TOPIC).projectOpened(project) + runUnderModalProgressIfIsEdt { + val startupManager = StartupManager.getInstance(project) as StartupManagerImpl + startupManager.initProject(null) + startupManager.runStartupActivities() + } + } + if (app.isDispatchThread || app.isUnitTestMode) { + fireRunnable.run() + } + else { + // Initialize ActionManager out of EDT to pass "assert !app.isDispatchThread()" in ActionManagerImpl + ActionManager.getInstance() + app.invokeLater(fireRunnable) + } + } - public @Nullable Project getProject() { - return myProject; + private fun createProject(): LightEditProjectImpl { + val start = System.nanoTime() + val project = LightEditProjectImpl() + LOG.info(LightEditProjectImpl::class.java.simpleName + " loaded in " + TimeoutUtil.getDurationMillis(start) + " ms") + return project + } } - public @NotNull Project getOrCreateProject() { - LightEditProjectImpl project = myProject; + @Volatile + private var projectImpl: LightEditProjectImpl? = null + + val project: Project? + get() = projectImpl + + fun getOrCreateProject(): Project { + var project = projectImpl if (project == null) { - boolean created = false; - synchronized (LOCK) { - if (myProject == null) { - myProject = createProject(); - created = true; + var created = false + synchronized(LOCK) { + if (projectImpl == null) { + projectImpl = createProject() + created = true } - project = myProject; + project = projectImpl } if (created) { - fireProjectOpened(project); - ApplicationManager.getApplication().getMessageBus().connect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() { - @Override - public void projectClosed(@NotNull Project project) { - if (project == myProject) { - synchronized (LOCK) { - myProject = null; - } + fireProjectOpened(project!!) + ApplicationManager.getApplication().messageBus.connect().subscribe(ProjectManager.TOPIC, object : ProjectManagerListener { + override fun projectClosed(project: Project) { + if (project === projectImpl) { + synchronized(LOCK) { projectImpl = null } } } - }); + }) } } - return project; + return project!! } - - private static void fireProjectOpened(@NotNull Project project) { - Application app = ApplicationManager.getApplication(); - Runnable fireRunnable = () -> { - // similar to com.intellij.openapi.project.impl.ProjectManagerExImplKt.openProject - app.getMessageBus().syncPublisher(ProjectManager.TOPIC).projectOpened(project); - try { - BuildersKt.runBlocking(EmptyCoroutineContext.INSTANCE, (scope, continuation) -> { - ((StartupManagerImpl)StartupManager.getInstance(project)).projectOpened(null, continuation); - return null; - }); - } - catch (InterruptedException e) { - throw new RuntimeException(e); - } - }; - if (app.isDispatchThread() || app.isUnitTestMode()) { - fireRunnable.run(); - } - else { - // Initialize ActionManager out of EDT to pass "assert !app.isDispatchThread()" in ActionManagerImpl - ActionManager.getInstance(); - app.invokeLater(fireRunnable); - } - } - - private static @NotNull LightEditProjectImpl createProject() { - long start = System.nanoTime(); - LightEditProjectImpl project = new LightEditProjectImpl(); - LOG.info(LightEditProjectImpl.class.getSimpleName() + " loaded in " + TimeoutUtil.getDurationMillis(start) + " ms"); - return project; - } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.kt b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.kt index 68cd3f2a0585..4b8fb769eb31 100644 --- a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.kt @@ -75,9 +75,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() if (activity is DumbAware) { project.coroutineScope.launch { if (activity is ProjectPostStartupActivity) { - DumbService.getInstance(project).runWithWaitForSmartModeDisabled().use { - startupManager.runActivityAndMeasureDuration(activity, descriptor.pluginId, project !is LightEditCompatible) - } + startupManager.runActivityAndMeasureDuration(activity, descriptor.pluginId, project !is LightEditCompatible) } else { startupManager.runActivityAndMeasureDuration(activity, pluginId) @@ -95,7 +93,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() } private val lock = Any() - private val startupActivities = ArrayDeque() + private val initProjectStartupActivities = ArrayDeque() private val postStartupActivities = ArrayDeque() @MagicConstant(intValues = [0, DUMB_AWARE_PASSED.toLong(), ALL_PASSED.toLong()]) @@ -104,7 +102,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() private val allActivitiesPassed = CompletableDeferred() @Volatile - private var isStartupActivitiesPassed = false + private var isInitProjectActivitiesPassed = false private fun checkNonDefaultProject() { LOG.assertTrue(!project.isDefault, "Please don't register startup activities for the default project: they won't ever be run") @@ -112,9 +110,9 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() override fun registerStartupActivity(runnable: Runnable) { checkNonDefaultProject() - LOG.assertTrue(!isStartupActivitiesPassed, "Registering startup activity that will never be run") + LOG.assertTrue(!isInitProjectActivitiesPassed, "Registering startup activity that will never be run") synchronized(lock) { - startupActivities.add(runnable) + initProjectStartupActivities.add(runnable) } } @@ -135,12 +133,12 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() LOG.error("Registering post-startup activity that will never be run (" + " disposed=${project.isDisposed}" + ", open=${project.isOpen}" + - ", passed=$isStartupActivitiesPassed" + ", passed=$isInitProjectActivitiesPassed" + ")") } } - override fun startupActivityPassed() = isStartupActivitiesPassed + override fun startupActivityPassed() = isInitProjectActivitiesPassed override fun postStartupActivityPassed(): Boolean { return when (postStartupActivitiesPassed) { @@ -152,17 +150,18 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() override fun getAllActivitiesPassedFuture() = allActivitiesPassed - suspend fun projectOpened(indicator: ProgressIndicator?) { - val app = ApplicationManager.getApplication() + suspend fun initProject(indicator: ProgressIndicator?) { // see https://github.com/JetBrains/intellij-community/blob/master/platform/service-container/overview.md#startup-activity - LOG.assertTrue(!isStartupActivitiesPassed) + LOG.assertTrue(!isInitProjectActivitiesPassed) runActivity("project startup") { - tracer.spanBuilder("run startup activities").useWithScope { - runStartUpActivities(indicator, app) - isStartupActivitiesPassed = true + tracer.spanBuilder("run init project activities").useWithScope { + runInitProjectActivities(indicator) + isInitProjectActivitiesPassed = true } } + } + suspend fun runStartupActivities() { // opened on startup StartUpMeasurer.compareAndSetCurrentState(LoadingState.COMPONENTS_LOADED, LoadingState.PROJECT_OPENED) // opened from the welcome screen @@ -170,6 +169,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() coroutineContext.ensureActive() + val app = ApplicationManager.getApplication() if (app.isUnitTestMode && !app.isDispatchThread) { runPostStartupActivities() } @@ -180,14 +180,14 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() } if (app.isUnitTestMode) { LOG.assertTrue(app.isDispatchThread) - @Suppress("TestOnlyProblems") waitAndProcessInvocationEventsInIdeEventQueue(this) } } } - private suspend fun runStartUpActivities(indicator: ProgressIndicator?, app: Application) { - runActivities(startupActivities) + private suspend fun runInitProjectActivities(indicator: ProgressIndicator?) { + runActivities(initProjectStartupActivities) + val app = ApplicationManager.getApplication() val extensionPoint = (app.extensionArea as ExtensionsAreaImpl).getExtensionPoint("com.intellij.startupActivity") // do not create extension if not allow-listed @@ -224,7 +224,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() // Must be executed in a pooled thread outside of project loading modal task. The only exclusion - test mode. private suspend fun runPostStartupActivities() { try { - LOG.assertTrue(isStartupActivitiesPassed) + LOG.assertTrue(isInitProjectActivitiesPassed) val snapshot = PerformanceWatcher.takeSnapshot() // strictly speaking, the activity is not sequential, because sub-activities are performed in different threads // (depending on dumb-awareness), but because there is no other concurrent phase, we measure it as a sequential activity @@ -237,36 +237,33 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() val isProjectLightEditCompatible = project is LightEditCompatible StartupActivity.POST_STARTUP_ACTIVITY.processExtensions { activity, pluginDescriptor -> if (activity is ProjectPostStartupActivity) { + runActivityAndMeasureDuration(activity, pluginDescriptor.pluginId, isProjectLightEditCompatible) + return@processExtensions + } + + @Suppress("SSBasedInspection") + if (activity is DumbAware) { dumbService.runWithWaitForSmartModeDisabled().use { - runActivityAndMeasureDuration(activity, pluginDescriptor.pluginId, isProjectLightEditCompatible) + runActivityAndMeasureDuration(activity, pluginDescriptor.pluginId) } return@processExtensions } else { - @Suppress("SSBasedInspection") - if (activity is DumbAware) { - dumbService.runWithWaitForSmartModeDisabled().use { - runActivityAndMeasureDuration(activity, pluginDescriptor.pluginId) - } - return@processExtensions + if (edtActivity.get() == null) { + edtActivity.set(StartUpMeasurer.startActivity("project post-startup edt activities")) } - else { - if (edtActivity.get() == null) { - edtActivity.set(StartUpMeasurer.startActivity("project post-startup edt activities")) - } - // DumbService.unsafeRunWhenSmart throws an assertion in LightEdit mode, see LightEditDumbService.unsafeRunWhenSmart - if (!isProjectLightEditCompatible) { - counter.incrementAndGet() - val traceContext = Context.current() - dumbService.unsafeRunWhenSmart { - traceContext.makeCurrent() - val duration = runActivityAndMeasureDuration(activity, pluginDescriptor.pluginId) - if (duration > EDT_WARN_THRESHOLD_IN_NANO) { - reportUiFreeze(uiFreezeWarned) - } - dumbUnawarePostActivitiesPassed(edtActivity, counter.decrementAndGet()) + // DumbService.unsafeRunWhenSmart throws an assertion in LightEdit mode, see LightEditDumbService.unsafeRunWhenSmart + if (!isProjectLightEditCompatible) { + counter.incrementAndGet() + val traceContext = Context.current() + dumbService.unsafeRunWhenSmart { + traceContext.makeCurrent() + val duration = runActivityAndMeasureDuration(activity, pluginDescriptor.pluginId) + if (duration > EDT_WARN_THRESHOLD_IN_NANO) { + reportUiFreeze(uiFreezeWarned) } + dumbUnawarePostActivitiesPassed(edtActivity, counter.decrementAndGet()) } } } @@ -324,7 +321,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() activity: ProjectPostStartupActivity, pluginId: PluginId, isProjectLightEditCompatible: Boolean - ): Long { + ) { val startTime = StartUpMeasurer.getCurrentTime() tracer.spanBuilder("run activity") .setAttribute(AttributeKey.stringKey("class"), activity.javaClass.name) @@ -334,7 +331,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() activity.execute(project) } } - return addCompletedActivity(startTime = startTime, runnableClass = activity.javaClass, pluginId = pluginId) + addCompletedActivity(startTime = startTime, runnableClass = activity.javaClass, pluginId = pluginId) } private suspend fun runPostStartupActivitiesRegisteredDynamically() { @@ -464,7 +461,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() @Synchronized fun prepareForNextTest() { synchronized(lock) { - startupActivities.clear() + initProjectStartupActivities.clear() postStartupActivities.clear() } } @@ -474,7 +471,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx() fun checkCleared() { try { synchronized(lock) { - assert(startupActivities.isEmpty()) { "Activities: $startupActivities" } + assert(initProjectStartupActivities.isEmpty()) { "Activities: $initProjectStartupActivities" } assert(postStartupActivities.isEmpty()) { "DumbAware Post Activities: $postStartupActivities" } } } diff --git a/platform/platform-impl/src/com/intellij/idea/ApplicationLoader.kt b/platform/platform-impl/src/com/intellij/idea/ApplicationLoader.kt index f815a8541435..290788417ffb 100644 --- a/platform/platform-impl/src/com/intellij/idea/ApplicationLoader.kt +++ b/platform/platform-impl/src/com/intellij/idea/ApplicationLoader.kt @@ -209,7 +209,6 @@ fun initApplication(rawArgs: List, prepareUiFuture: Deferred) { } } -@OptIn(ExperimentalCoroutinesApi::class) private suspend fun prepareStart(app: ApplicationImpl, initAppActivity: Activity, pluginSet: PluginSet, mainScope: CoroutineScope) { coroutineScope { app.preloadServices( @@ -243,10 +242,9 @@ private suspend fun prepareStart(app: ApplicationImpl, initAppActivity: Activity createAppLocatorFile() } - if (!app.isUnitTestMode && !app.isHeadlessEnvironment && - java.lang.Boolean.parseBoolean(System.getProperty("enable.activity.preloading", "true"))) { + if (!app.isUnitTestMode && !app.isHeadlessEnvironment && System.getProperty("enable.activity.preloading", "true").toBoolean()) { // do not execute as a single long task, make sure that other more important tasks may slip in between - launchAndMeasure("preloading activity executing", Dispatchers.Default.limitedParallelism(1)) { + launchAndMeasure("preloading activity executing") { executePreloadActivities(app) } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index 4e124d37f930..e901ab529a42 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -197,17 +197,10 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen } }); connection.subscribe(ProjectManager.TOPIC, new ProjectManagerListener() { - @Override - public void projectOpened(@NotNull Project project) { - if (project == myProject) { - FileEditorManagerImpl.this.projectOpened(connection); - } - } - @Override public void projectClosing(@NotNull Project project) { if (project == myProject) { - // Dispose created editors. We do not use use closeEditor method because + // Dispose created editors. We do not use closeEditor method because // it fires event and changes history. closeAllFiles(); } @@ -545,6 +538,7 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen getActiveSplittersAsync().onSuccess(splitters -> splitters.updateFileName(null)); } + @SuppressWarnings("removal") @Override public VirtualFile getFile(@NotNull FileEditor editor) { EditorComposite editorComposite = getComposite(editor); @@ -940,7 +934,7 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen /** * @param file to be opened. Unlike openFile method, file can be - * invalid. For example, all file were invalidate and they are being + * invalid. For example, all file where invalidate, and they are being * removed one by one. If we have removed one invalid file, then another * invalid file become selected. That's why we do not require that * passed file is valid. @@ -1202,7 +1196,7 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen } if (state == null && newEditor) { // We have to try to get state from the history only in case - // if editor is not opened. Otherwise history entry might have a state + // if editor is not opened. Otherwise, history entry might have a state // out of sync with the current editor state. state = EditorHistoryManager.getInstance(myProject).getState(file, provider); } @@ -1415,7 +1409,7 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen return getSelectedTextEditor(false); } - public Editor getSelectedTextEditor(boolean lockfree) { + public Editor getSelectedTextEditor(boolean isLockFree) { if (!ClientId.isCurrentlyUnderLocalId()) { ClientFileEditorManager clientManager = getClientFileEditorManager(); if (clientManager == null) { @@ -1425,11 +1419,11 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen return selectedEditor instanceof TextEditor ? ((TextEditor)selectedEditor).getEditor() : null; } - if (!lockfree) { + if (!isLockFree) { assertDispatchThread(); } - EditorWindow currentWindow = lockfree ? getMainSplitters().getCurrentWindow() : getSplitters().getCurrentWindow(); + EditorWindow currentWindow = isLockFree ? getMainSplitters().getCurrentWindow() : getSplitters().getCurrentWindow(); if (currentWindow != null) { EditorComposite selectedEditor = currentWindow.getSelectedComposite(); if (selectedEditor != null && selectedEditor.getSelectedEditor() instanceof TextEditor) { @@ -1686,7 +1680,8 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen myListenerList.remove(listener); } - protected void projectOpened(@NotNull MessageBusConnection connection) { + @ApiStatus.Internal + public final void init() { //myFocusWatcher.install(myWindows.getComponent ()); getMainSplitters().startListeningFocus(); @@ -1695,6 +1690,8 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen // updates tabs colors fileStatusManager.addFileStatusListener(new MyFileStatusListener(), myProject); } + + MessageBusConnection connection = myProject.getMessageBus().connect(this); connection.subscribe(FileTypeManager.TOPIC, new MyFileTypeListener()); connection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyRootsListener()); connection.subscribe(AdditionalLibraryRootsListener.TOPIC, new MyRootsListener()); @@ -2127,7 +2124,7 @@ public abstract class FileEditorManagerImpl extends FileEditorManagerEx implemen /** * Gets notifications from UISetting component to track changes of RECENT_FILES_LIMIT - * and EDITOR_TAB_LIMIT, etc values. + * and EDITOR_TAB_LIMIT, etc. values. */ private final class MyUISettingsListener implements UISettingsListener { @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/OpenFilesActivity.kt b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/OpenFilesActivity.kt index 56d71b295c32..0d137668b221 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/OpenFilesActivity.kt +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/OpenFilesActivity.kt @@ -18,12 +18,17 @@ import com.intellij.openapi.project.isNotificationSilentMode import com.intellij.openapi.startup.InitProjectActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext internal class OpenFilesActivity : InitProjectActivity { override suspend fun run(project: Project) { ProgressManager.getInstance().progressIndicator?.text = IdeBundle.message("progress.text.reopening.files") val fileEditorManager = FileEditorManager.getInstance(project) as? FileEditorManagerImpl ?: return + withContext(Dispatchers.EDT) { + fileEditorManager.init() + } + val editorSplitters = fileEditorManager.mainSplitters val panel = editorSplitters.restoreEditors() (project as ProjectEx).coroutineScope.launch(Dispatchers.EDT + ModalityState.NON_MODAL.asContextElement()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.kt b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.kt index 8d5dc85617cb..8c42928a4913 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.kt @@ -4,6 +4,7 @@ package com.intellij.openapi.project.impl import com.intellij.configurationStore.runInAutoSaveDisabledMode import com.intellij.configurationStore.saveSettings import com.intellij.diagnostic.ActivityCategory +import com.intellij.diagnostic.LoadingState import com.intellij.diagnostic.PluginException import com.intellij.diagnostic.StartUpMeasurer import com.intellij.ide.impl.runUnderModalProgressIfIsEdt @@ -358,7 +359,7 @@ open class ProjectImpl(filePath: Path, projectName: String?) override fun getContainerDescriptor(pluginDescriptor: IdeaPluginDescriptorImpl) = pluginDescriptor.projectContainerDescriptor override fun setProgressDuringInit(indicator: ProgressIndicator) { - indicator.fraction = getPercentageOfComponentsLoaded() / if (ourClassesAreLoaded) 10 else 2 + indicator.fraction = getPercentageOfComponentsLoaded() / if (LoadingState.PROJECT_OPENED.isOccurred) 10 else 2 } override fun save() { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt index e77c46860949..724acbda82c6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt @@ -97,10 +97,11 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable { init { val connection = ApplicationManager.getApplication().messageBus.connect() connection.subscribe(TOPIC, object : ProjectManagerListener { + @Suppress("removal") override fun projectOpened(project: Project) { for (listener in getAllListeners(project)) { try { - @Suppress("DEPRECATION") + @Suppress("DEPRECATION", "removal") listener.projectOpened(project) } catch (e: Exception) { @@ -292,6 +293,7 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable { } app.assertIsWriteThread() + @Suppress("TestOnlyProblems") if (isLight(project)) { // if we close project at the end of the test, just mark it closed; // if we are shutting down the entire test framework, proceed to full dispose @@ -562,18 +564,10 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable { throw CancellationException("not trusted") } - val waitEdtActivity = StartUpMeasurer.startActivity("placing calling projectOpened on event queue") - val indicator = ProgressManager.getInstance().progressIndicator - if (indicator != null) { - indicator.text = if (ApplicationManager.getApplication().isInternal) "Waiting on event queue..." // NON-NLS (internal mode) - else ProjectBundle.message("project.preparing.workspace") - indicator.isIndeterminate = true - } - tracer.spanBuilder("open project") .setAttribute(AttributeKey.stringKey("project"), project.name) .useWithScope { - runStartupActivities(project, indicator, isRunStartUpActivitiesEnabled(project), waitEdtActivity) + runInitProjectActivities(project) } } @@ -613,6 +607,11 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable { disableAutoSaveToken.finish() } + if (isRunStartUpActivitiesEnabled(project)) { + (StartupManager.getInstance(project) as StartupManagerImpl).runStartupActivities() + } + LifecycleUsageTriggerCollector.onProjectOpened(project) + options.callback?.projectOpened(project, module ?: ModuleManager.getInstance(project).modules[0]) return project } @@ -848,69 +847,51 @@ private fun message(e: Throwable): String { @Internal @VisibleForTesting -suspend fun runStartupActivities(project: Project, - indicator: ProgressIndicator?, - runStartUpActivities: Boolean, - waitEdtActivity: Activity?) { +suspend fun runInitProjectActivities(project: Project) { val traceContext = Context.current() - withContext(Dispatchers.EDT) { - waitEdtActivity?.end() - - if (indicator != null && ApplicationManager.getApplication().isInternal) { - indicator.text = "Running project opened tasks..." // NON-NLS (internal mode) + coroutineScope { + launch { + (StartupManager.getInstance(project) as StartupManagerImpl).initProject(null) } - LOG.debug("projectOpened") + val waitEdtActivity = StartUpMeasurer.startActivity("placing calling projectOpened on event queue") + launch(Dispatchers.EDT) { + waitEdtActivity.end() - val activity = StartUpMeasurer.startActivity("project opened callbacks") - - runActivity("projectOpened event executing") { - tracer.spanBuilder("execute projectOpened handlers").setParent(traceContext).useWithScope { - @Suppress("DEPRECATION") - ApplicationManager.getApplication().messageBus.syncPublisher(ProjectManager.TOPIC).projectOpened(project) - } - } - - coroutineContext.ensureActive() - - @Suppress("DEPRECATION") - (project as ComponentManagerImpl) - .processInitializedComponents(com.intellij.openapi.components.ProjectComponent::class.java) { component, pluginDescriptor -> - coroutineContext.ensureActive() - try { - val componentActivity = StartUpMeasurer.startActivity(component.javaClass.name, ActivityCategory.PROJECT_OPEN_HANDLER, - pluginDescriptor.pluginId.idString) - component.projectOpened() - componentActivity.end() - } - catch (e: CancellationException) { - throw e - } - catch (e: ProcessCanceledException) { - throw e - } - catch (e: Throwable) { - LOG.error(e) + val activity = StartUpMeasurer.startActivity("project opened callbacks") + runActivity("projectOpened event executing") { + tracer.spanBuilder("execute projectOpened handlers").setParent(traceContext).useWithScope { + @Suppress("DEPRECATION", "removal") + ApplicationManager.getApplication().messageBus.syncPublisher(ProjectManager.TOPIC).projectOpened(project) } } - activity.end() - } + coroutineContext.ensureActive() - ProjectImpl.ourClassesAreLoaded = true + @Suppress("DEPRECATION") + (project as ComponentManagerImpl) + .processInitializedComponents(com.intellij.openapi.components.ProjectComponent::class.java) { component, pluginDescriptor -> + coroutineContext.ensureActive() + try { + val componentActivity = StartUpMeasurer.startActivity(component.javaClass.name, ActivityCategory.PROJECT_OPEN_HANDLER, + pluginDescriptor.pluginId.idString) + component.projectOpened() + componentActivity.end() + } + catch (e: CancellationException) { + throw e + } + catch (e: ProcessCanceledException) { + throw e + } + catch (e: Throwable) { + LOG.error(e) + } + } - if (runStartUpActivities) { - val app = ApplicationManager.getApplication() - if (indicator != null && app.isInternal) { - indicator.text = IdeBundle.message("startup.indicator.text.running.startup.activities") - } - - tracer.spanBuilder("StartupManager.projectOpened").useWithScope { - (StartupManager.getInstance(project) as StartupManagerImpl).projectOpened(indicator) + activity.end() } } - - LifecycleUsageTriggerCollector.onProjectOpened(project) } private val LOG = logger() @@ -992,6 +973,7 @@ private fun ensureCouldCloseIfUnableToSave(project: Project): Boolean { } } + @Suppress("HardCodedStringLiteral") return Messages.showYesNoDialog(project, message.toString(), IdeUICustomization.getInstance().projectMessage("dialog.title.unsaved.project"), Messages.getWarningIcon()) == Messages.YES diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacDockDelegate.java b/platform/platform-impl/src/com/intellij/ui/mac/MacDockDelegate.java index ed6bf985a27f..e66589c7391f 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacDockDelegate.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacDockDelegate.java @@ -1,9 +1,8 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ui.mac; import com.intellij.ide.DataManager; import com.intellij.ide.RecentProjectListActionProvider; -import com.intellij.ide.RecentProjectsManager; import com.intellij.ide.ReopenProjectAction; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; @@ -15,7 +14,6 @@ import com.intellij.openapi.wm.impl.SystemDock; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.List; /** * @author Denis Fokin @@ -57,14 +55,9 @@ public final class MacDockDelegate implements SystemDock.Delegate { @Override public void updateRecentProjectsMenu () { - RecentProjectsManager projectsManager = RecentProjectsManager.getInstance(); - if (projectsManager == null) { - return; - } - List recentProjectActions = RecentProjectListActionProvider.getInstance().getActions(false); recentProjectsMenu.removeAll(); - for (AnAction action : recentProjectActions) { + for (AnAction action : RecentProjectListActionProvider.getInstance().getActions(false)) { MenuItem menuItem = new MenuItem(((ReopenProjectAction)action).getProjectNameToDisplay()); menuItem.addActionListener(new ActionListener() { @Override diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index f3def2b2ed1c..534b2d2afafe 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -3,6 +3,11 @@ + + + + @@ -106,11 +111,6 @@ - - - - + + @@ -125,6 +129,8 @@ + + diff --git a/platform/platform-tests/testSrc/com/intellij/module/ExplicitModuleGroupTest.kt b/platform/platform-tests/testSrc/com/intellij/module/ExplicitModuleGroupTest.kt index 71ef4a1ff4dc..34493f14206e 100644 --- a/platform/platform-tests/testSrc/com/intellij/module/ExplicitModuleGroupTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/module/ExplicitModuleGroupTest.kt @@ -1,19 +1,5 @@ -/* - * Copyright 2000-2017 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-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.module import com.intellij.ide.projectView.impl.ModuleGroup @@ -68,7 +54,7 @@ class ExplicitModuleGroupTest : HeavyPlatformTestCase() { private fun createModuleInGroup(name: String, vararg path: String): Module { val module = createModule(name) - val model = ModuleManager.getInstance(myProject).modifiableModel + val model = ModuleManager.getInstance(myProject).getModifiableModel() model.setModuleGroupPath(module, path) runWriteAction { model.commit() } return module diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/RecentProjectsTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/RecentProjectsTest.kt index b855ff6e6e8b..ecd3ffceb58c 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/RecentProjectsTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/RecentProjectsTest.kt @@ -6,6 +6,7 @@ package com.intellij.openapi.project.impl import com.intellij.ide.* import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.project.ex.ProjectManagerEx import com.intellij.project.stateStore import com.intellij.testFramework.* import com.intellij.testFramework.assertions.Assertions.assertThat @@ -13,12 +14,13 @@ import com.intellij.ui.DeferredIconImpl import com.intellij.util.PathUtil import com.intellij.util.messages.SimpleMessageBusConnection import com.intellij.util.ui.EmptyIcon +import kotlinx.coroutines.runBlocking import org.junit.ClassRule import org.junit.Rule import org.junit.Test import org.junit.rules.ExternalResource import java.nio.file.Path -import java.nio.file.Paths +import java.util.* class RecentProjectsTest { companion object { @@ -44,7 +46,7 @@ class RecentProjectsTest { val tempDir = TemporaryDirectory() @Test - fun testMostRecentOnTop() { + fun testMostRecentOnTop() = runBlocking { val p1 = createAndOpenProject("p1") val p2 = createAndOpenProject("p2") val p3 = createAndOpenProject("p3") @@ -57,7 +59,7 @@ class RecentProjectsTest { } @Test - fun testGroupsOrder() { + fun testGroupsOrder() = runBlocking { val p1 = createAndOpenProject("p1") val p2 = createAndOpenProject("p2") val p3 = createAndOpenProject("p3") @@ -81,19 +83,24 @@ class RecentProjectsTest { } @Test - fun timestampForOpenProjectUpdatesWhenGetStateCalled() { + fun timestampForOpenProjectUpdatesWhenGetStateCalled(): Unit = runBlocking { val z1 = tempDir.newPath("z1") - var project = PlatformTestUtil.loadAndOpenProject(z1, disposableRule.disposable) + val projectManager = ProjectManagerEx.getInstanceEx() + var project = projectManager.openProjectAsync(z1, createTestOpenProjectOptions(runPostStartUpActivities = false))!! try { + val recentProjectManager = RecentProjectsManagerBase.getInstanceEx() + recentProjectManager.runProjectPostStartupActivity(project) + val timestamp = getProjectOpenTimestamp("z1") - PlatformTestUtil.forceCloseProjectWithoutSaving(project) - project = PlatformTestUtil.loadAndOpenProject(z1, disposableRule.disposable) - RecentProjectsManagerBase.getInstanceEx().updateLastProjectPath() + projectManager.forceCloseProjectAsync(project) + project = projectManager.openProjectAsync(z1, createTestOpenProjectOptions(runPostStartUpActivities = false))!! + recentProjectManager.runProjectPostStartupActivity(project) + recentProjectManager.updateLastProjectPath() // "Timestamp for opened project has not been updated" assertThat(getProjectOpenTimestamp("z1")).isGreaterThan(timestamp) } finally { - PlatformTestUtil.forceCloseProjectWithoutSaving(project) + projectManager.forceCloseProjectAsync(project) } } @@ -102,7 +109,7 @@ class RecentProjectsTest { // For Rider val rpm = (RecentProjectsManager.getInstance() as RecentProjectsManagerBase) - val projectDir = Paths.get("${PlatformTestUtil.getPlatformTestDataPath()}/recentProjects/dotNetSampleRecent/Povysh") + val projectDir = Path.of("${PlatformTestUtil.getPlatformTestDataPath()}/recentProjects/dotNetSampleRecent/Povysh") val slnFile = projectDir.resolve("Povysh.sln") val icon = (rpm.getProjectIcon(slnFile.toString(), false) as DeferredIconImpl<*>).evaluate() @@ -120,15 +127,24 @@ class RecentProjectsTest { return -1 } - private fun doReopenCloseAndCheck(projectPath: Path, vararg results: String) { - val project = PlatformTestUtil.loadAndOpenProject(projectPath, disposableRule.disposable) - PlatformTestUtil.forceCloseProjectWithoutSaving(project) + private suspend fun doReopenCloseAndCheck(projectPath: Path, vararg results: String) { + openProjectAndClose(projectPath) checkRecents(*results) } - private fun doReopenCloseAndCheckGroups(projectPath: Path, results: List) { - val project = PlatformTestUtil.loadAndOpenProject(projectPath, disposableRule.disposable) - PlatformTestUtil.forceCloseProjectWithoutSaving(project) + private suspend fun openProjectAndClose(projectPath: Path) { + val projectManager = ProjectManagerEx.getInstanceEx() + val project = projectManager.openProjectAsync(projectPath, createTestOpenProjectOptions(runPostStartUpActivities = false))!! + try { + RecentProjectsManagerBase.getInstanceEx().runProjectPostStartupActivity(project) + } + finally { + projectManager.forceCloseProjectAsync(project) + } + } + + private suspend fun doReopenCloseAndCheckGroups(projectPath: Path, results: List) { + openProjectAndClose(projectPath) checkGroups(results) } @@ -150,17 +166,21 @@ class RecentProjectsTest { assertThat(recentGroups).isEqualTo(groups) } - private fun createAndOpenProject(name: String): Path { + private suspend fun createAndOpenProject(name: String): Path { val path = tempDir.newPath(name) - var project = PlatformTestUtil.loadAndOpenProject(path, disposableRule.disposable) + val projectManager = ProjectManagerEx.getInstanceEx() + var project = projectManager.openProjectAsync(path, createTestOpenProjectOptions(runPostStartUpActivities = false))!! try { + val recentProjectManager = RecentProjectsManagerBase.getInstanceEx() + recentProjectManager.runProjectPostStartupActivity(project) project.stateStore.saveComponent(RecentProjectsManager.getInstance() as RecentProjectsManagerBase) - PlatformTestUtil.forceCloseProjectWithoutSaving(project) - project = PlatformTestUtil.loadAndOpenProject(path, disposableRule.disposable) + projectManager.forceCloseProjectAsync(project) + project = projectManager.openProjectAsync(path, createTestOpenProjectOptions(runPostStartUpActivities = false))!! + recentProjectManager.runProjectPostStartupActivity(project) return path } finally { - PlatformTestUtil.forceCloseProjectWithoutSaving(project) + projectManager.forceCloseProjectAsync(project) } } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/navigation/JBNavigateCommandTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/navigation/JBNavigateCommandTest.kt index 886162046ea3..fba6dbafe7ce 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/navigation/JBNavigateCommandTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/project/impl/navigation/JBNavigateCommandTest.kt @@ -3,6 +3,7 @@ package com.intellij.openapi.project.impl.navigation +import com.intellij.ide.RecentProjectsManagerBase import com.intellij.navigation.areOriginsEqual import com.intellij.openapi.application.EDT import com.intellij.openapi.application.JBProtocolCommand @@ -61,18 +62,17 @@ class JBNavigateCommandTest : NavigationTestBase() { @Test fun pathOpenProject(): Unit = runBlocking { val projectManager = ProjectManagerEx.getInstanceEx() + val prevProjects = projectManager.openProjects.toHashSet() + createOrLoadProject(tempDir, useDefaultProjectSettings = false) { project -> setUpProject(project) + RecentProjectsManagerBase.getInstanceEx().runProjectPostStartupActivity(project) } - - val prevProjects = projectManager.openProjects.toHashSet() try { - ProjectManagerEx.getInstanceEx().forceCloseProjectAsync(project) val result = withContext(Dispatchers.EDT) { navigate(mapOf("path" to "A.java")) } assertThat(result).isNull() - yield() withContext(Dispatchers.EDT) { yield() } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/IndexableFilesRegularTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/IndexableFilesRegularTest.kt index 3839c9590092..38120f5ad1e6 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/IndexableFilesRegularTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/IndexableFilesRegularTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.roots.impl.indexing import com.intellij.openapi.application.runWriteAction @@ -21,7 +21,6 @@ import com.intellij.util.indexing.FileBasedIndexEx import com.intellij.util.indexing.FileBasedIndexImpl import com.intellij.util.indexing.IndexableSetContributor import org.junit.Test -import java.util.* import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -347,9 +346,9 @@ class IndexableFilesRegularTest : IndexableFilesBaseTest() { } } assertIndexableFiles(contentFileToUnload.file, contentFileToRetain.file) - ModuleManager.getInstance(project).setUnloadedModules(Arrays.asList("moduleToUnload")) + ModuleManager.getInstance(project).setUnloadedModulesSync(listOf("moduleToUnload")) assertIndexableFiles(contentFileToRetain.file) - ModuleManager.getInstance(project).setUnloadedModules(Collections.emptyList()) + ModuleManager.getInstance(project).setUnloadedModulesSync(emptyList()) assertIndexableFiles(contentFileToUnload.file, contentFileToRetain.file) } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/ProjectStructureDsl.kt b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/ProjectStructureDsl.kt index c81e1289cd5c..aad927971f9e 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/ProjectStructureDsl.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/impl/indexing/ProjectStructureDsl.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.roots.impl.indexing import com.intellij.openapi.application.runWriteAction @@ -287,7 +287,7 @@ private fun createJavaModule(project: Project, moduleName: String, moduleRootDir val type = ModuleTypeManager.getInstance().findByID(ModuleTypeId.JAVA_MODULE) return WriteCommandAction.writeCommandAction(project).compute( ThrowableComputable { - val moduleModel = ModuleManager.getInstance(project).modifiableModel + val moduleModel = ModuleManager.getInstance(project).getModifiableModel() val module = moduleModel.newModule(moduleRootDirectory.resolve("$moduleName.iml"), type.id) moduleModel.commit() module diff --git a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java index bb1ba90f42e5..9dc65ba4e46f 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java +++ b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleComponent.java @@ -11,16 +11,14 @@ import com.intellij.openapi.project.Project; * {@link #initComponent()}, {@link #moduleAdded()} methods will be called for each module even if user doesn't use * any feature of your plugin. Also, plugins declaring module components do not support dynamic loading. */ -@Deprecated +@Deprecated(forRemoval = true) public interface ModuleComponent extends BaseComponent { /** - * Invoked when the project corresponding to this component instance is opened.

- * Note that components may be created for even unopened projects and this method can be never - * invoked for a particular component instance (for example for default project). - * - * @deprecated Please use {@link com.intellij.openapi.project.ProjectManager#TOPIC} ({@link com.intellij.openapi.project.ProjectManagerListener#projectOpened(Project)} (Project, Module)}) + * @deprecated Do not use. + * Post start-up activity + * maybe an alternative. */ - @Deprecated + @Deprecated(forRemoval = true) default void projectOpened() { } @@ -31,7 +29,7 @@ public interface ModuleComponent extends BaseComponent { * * @deprecated Please use {@link com.intellij.openapi.project.ProjectManager#TOPIC} ({@link com.intellij.openapi.project.ProjectManagerListener#projectClosed(Project)} (Project, Module)}) */ - @Deprecated + @Deprecated(forRemoval = true) default void projectClosed() { } @@ -41,7 +39,7 @@ public interface ModuleComponent extends BaseComponent { * * @deprecated Consider to use {@link com.intellij.ProjectTopics#MODULES} ({@link com.intellij.openapi.project.ModuleListener#moduleAdded(Project, Module)}) */ - @Deprecated + @Deprecated(forRemoval = true) default void moduleAdded() { } } diff --git a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.kt b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.kt index 6ef17a721139..3b2f744c663c 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.kt +++ b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleManager.kt @@ -1,36 +1,33 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.openapi.module; +package com.intellij.openapi.module -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.NlsSafe; -import com.intellij.openapi.util.SimpleModificationTracker; -import com.intellij.util.graph.Graph; -import org.jdom.JDOMException; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.SimpleModificationTracker +import com.intellij.util.graph.Graph +import org.jdom.JDOMException +import org.jetbrains.annotations.ApiStatus +import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.TestOnly +import java.io.File +import java.io.IOException +import java.nio.file.Path /** * Provides services for working with the modules of a project. */ @ApiStatus.NonExtendable -public abstract class ModuleManager extends SimpleModificationTracker { - /** - * Returns the module manager instance for the current project. - * - * @param project the project for which the module manager is requested. - * @return the module manager instance. - */ - public static ModuleManager getInstance(@NotNull Project project) { - return project.getComponent(ModuleManager.class); +abstract class ModuleManager : SimpleModificationTracker() { + companion object { + /** + * Returns the module manager instance for the current project. + * + * @param project the project for which the module manager is requested. + * @return the module manager instance. + */ + @JvmStatic + fun getInstance(project: Project): ModuleManager = project.getComponent(ModuleManager::class.java) + + fun getInstanceIfDefined(project: Project): ModuleManager? = project.getComponent(ModuleManager::class.java) } /** @@ -41,32 +38,29 @@ public abstract class ModuleManager extends SimpleModificationTracker { * @param moduleTypeId the ID of the module type to create. * @return the module instance. */ - public abstract @NotNull Module newModule(@NotNull @NonNls String filePath, @NotNull String moduleTypeId); + abstract fun newModule(filePath: @NonNls String, moduleTypeId: String): Module - public @NotNull Module newModule(@NotNull Path file, @NotNull String moduleTypeId) { - return newModule(file.toString().replace(File.separatorChar, '/'), moduleTypeId); + fun newModule(file: Path, moduleTypeId: String): Module { + return newModule(file.toString().replace(File.separatorChar, '/'), moduleTypeId) } /** * Creates a non-persistent module of the specified type and adds it to the project - * to which the module manager is related. {@link #commit()} must be called to + * to which the module manager is related. [.commit] must be called to * bring the changes in effect. * - * In contrast with modules created by {@link #newModule(String, String)}, + * In contrast with modules created by [.newModule], * non-persistent modules aren't stored on a filesystem and aren't being written * in a project XML file. When IDE closes, all non-persistent modules vanishes out. */ @ApiStatus.Experimental - @NotNull - public Module newNonPersistentModule(@NotNull String moduleName, @NotNull String id) { - throw new UnsupportedOperationException(); + open fun newNonPersistentModule(moduleName: String, id: String): Module { + throw UnsupportedOperationException() } - /** - * @deprecated Use {@link #loadModule(Path)} - */ - @Deprecated - public abstract @NotNull Module loadModule(@NotNull String filePath) throws IOException, JDOMException, ModuleWithNameAlreadyExists; + @Deprecated("Use {@link #loadModule(Path)}") + @Throws(IOException::class, JDOMException::class, ModuleWithNameAlreadyExists::class) + abstract fun loadModule(filePath: String): Module /** * Loads a module from an .iml file with the specified path and adds it to the project. @@ -76,21 +70,22 @@ public abstract class ModuleManager extends SimpleModificationTracker { * @throws IOException if an I/O error occurred when loading the module file. * @throws ModuleWithNameAlreadyExists if a module with such a name already exists in the project. */ - public abstract @NotNull Module loadModule(@NotNull Path file) throws IOException, ModuleWithNameAlreadyExists; + @Throws(IOException::class, ModuleWithNameAlreadyExists::class) + abstract fun loadModule(file: Path): Module /** * Disposes of the specified module and removes it from the project. * * @param module the module to remove. */ - public abstract void disposeModule(@NotNull Module module); + abstract fun disposeModule(module: Module) /** * Returns the list of all modules in the project. * * @return the array of modules. */ - public abstract Module @NotNull [] getModules(); + abstract val modules: Array /** * Returns the project module with the specified name. @@ -98,8 +93,7 @@ public abstract class ModuleManager extends SimpleModificationTracker { * @param name the name of the module to find. * @return the module instance, or null if no module with such name exists. */ - @Nullable - public abstract Module findModuleByName(@NonNls @NotNull String name); + abstract fun findModuleByName(name: @NonNls String): Module? /** * Returns the list of modules sorted by dependency (the modules which do not depend @@ -108,7 +102,7 @@ public abstract class ModuleManager extends SimpleModificationTracker { * * @return the sorted array of modules. */ - public abstract Module @NotNull [] getSortedModules(); + abstract val sortedModules: Array /** * Returns the module comparator which can be used for sorting modules by dependency @@ -117,35 +111,32 @@ public abstract class ModuleManager extends SimpleModificationTracker { * * @return the module comparator instance. */ - @NotNull - public abstract Comparator moduleDependencyComparator(); + abstract fun moduleDependencyComparator(): Comparator /** * Returns the list of modules which directly depend on the specified module. * * @param module the module for which the list of dependent modules is requested. - * @return list of modules that depend on given module. - * @see ModuleUtilCore#getAllDependentModules(Module) + * @return list of *modules that depend on* given module. + * @see ModuleUtilCore.getAllDependentModules */ - @NotNull - public abstract List getModuleDependentModules(@NotNull Module module); + abstract fun getModuleDependentModules(module: Module): List /** * Checks if one of the specified modules directly depends on the other module. * * @param module the module to check the dependency for. - * @param onModule the module on which {@code module} may depend. - * @return true if {@code module} directly depends on {@code onModule}, false otherwise. + * @param onModule the module on which `module` may depend. + * @return true if `module` directly depends on `onModule`, false otherwise. */ - public abstract boolean isModuleDependent(@NotNull Module module, @NotNull Module onModule); + abstract fun isModuleDependent(module: Module, onModule: Module): Boolean /** * Returns the graph of dependencies between modules in the project. * * @return the module dependency graph. */ - @NotNull - public abstract Graph moduleGraph(); + abstract fun moduleGraph(): Graph /** * Returns the graph of dependencies between modules in the project. @@ -153,8 +144,7 @@ public abstract class ModuleManager extends SimpleModificationTracker { * @param includeTests whether test-only dependencies should be included * @return the module dependency graph. */ - @NotNull - public abstract Graph moduleGraph(boolean includeTests); + abstract fun moduleGraph(includeTests: Boolean): Graph /** * Returns the model for the list of modules in the project, which can be used to add, @@ -162,49 +152,48 @@ public abstract class ModuleManager extends SimpleModificationTracker { * * @return the modifiable model instance. */ - @NotNull - public abstract ModifiableModuleModel getModifiableModel(); - + abstract fun getModifiableModel(): ModifiableModuleModel /** * Returns the path to the group to which the specified module belongs, as an array of group names starting from the project root. - *

- * Use {@link ModuleGrouper#getGroupPath(Module)} instead. Explicit module groups will be replaced - * by automatic module grouping accordingly to qualified names of modules, see IDEA-166061 for details. - *

+ * + * + * **Use [ModuleGrouper.getGroupPath] instead.** Explicit module groups will be replaced + * by automatic module grouping accordingly to qualified names of modules, see [IDEA-166061](https://youtrack.jetbrains.com/issue/IDEA-166061) for details. + * * @param module the module for which the path is requested. * @return the path to the group for the module, or null if the module does not belong to any group. */ - public abstract @NlsSafe String @Nullable [] getModuleGroupPath(@NotNull Module module); + abstract fun getModuleGroupPath(module: Module): Array? - public abstract boolean hasModuleGroups(); + abstract fun hasModuleGroups(): Boolean /** * @return description of all modules in the project including unloaded */ - @ApiStatus.Experimental - @NotNull - public abstract Collection getAllModuleDescriptions(); + @get:ApiStatus.Experimental + abstract val allModuleDescriptions: Collection + + @get:ApiStatus.Experimental + abstract val unloadedModuleDescriptions: Collection @ApiStatus.Experimental - @NotNull - public abstract Collection getUnloadedModuleDescriptions(); + abstract fun getUnloadedModuleDescription(moduleName: String): UnloadedModuleDescription? - @ApiStatus.Experimental - @Nullable - public abstract UnloadedModuleDescription getUnloadedModuleDescription(@NotNull String moduleName); - - @NotNull - public abstract ModuleGrouper getModuleGrouper(@Nullable ModifiableModuleModel model); + abstract fun getModuleGrouper(model: ModifiableModuleModel?): ModuleGrouper /** * Specify list of modules which will be unloaded from the project. * @see UnloadedModuleDescription */ @ApiStatus.Experimental - public abstract void setUnloadedModules(@NotNull List unloadedModuleNames); + abstract suspend fun setUnloadedModules(unloadedModuleNames: List) + + @Deprecated("Use setUnloadedModules") + @TestOnly + abstract fun setUnloadedModulesSync(unloadedModuleNames: List) @ApiStatus.Experimental - public void removeUnloadedModules(@NotNull Collection unloadedModules) { + open fun removeUnloadedModules(unloadedModules: Collection) { } -} +} \ No newline at end of file diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ModuleListener.java b/platform/projectModel-api/src/com/intellij/openapi/project/ModuleListener.java index e34a9f83fe50..0e51fc2f9dcc 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/project/ModuleListener.java +++ b/platform/projectModel-api/src/com/intellij/openapi/project/ModuleListener.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.project; import com.intellij.ProjectTopics; @@ -21,6 +21,12 @@ public interface ModuleListener extends EventListener { default void moduleAdded(@NotNull Project project, @NotNull Module module) { } + default void modulesAdded(@NotNull Project project, @NotNull List modules) { + for (Module module : modules) { + moduleAdded(project, module); + } + } + default void beforeModuleRemoved(@NotNull Project project, @NotNull Module module) { } diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java index 4c149d48032b..7228214e24ee 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java +++ b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java @@ -17,6 +17,7 @@ public interface ProjectManagerListener extends EventListener { * Post start-up activity * maybe an alternative. */ + @Deprecated(forRemoval = true) default void projectOpened(@NotNull Project project) { } diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java index a500ee308aeb..63f6367030b4 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java @@ -28,6 +28,8 @@ public abstract class ProjectRootManagerEx extends ProjectRootManager { public abstract void makeRootsChange(@NotNull Runnable runnable, @NotNull RootsChangeRescanningInfo changes); + public abstract @NotNull AutoCloseable withRootsChange(@NotNull RootsChangeRescanningInfo changes); + public abstract void markRootsForRefresh(); public abstract void mergeRootsChangesDuring(@NotNull Runnable runnable); diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt b/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt index 6a6fa9fee265..447f5790f749 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/EmptyModuleManager.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.module import com.intellij.openapi.module.impl.createGrouper @@ -18,11 +18,13 @@ class EmptyModuleManager(private val project: Project) : ModuleManager() { override fun disposeModule(module: Module) { } - override fun getModules(): Array = emptyArray() + override val modules: Array + get() = emptyArray() override fun findModuleByName(name: String): Nothing? = null - override fun getSortedModules(): Array = emptyArray() + override val sortedModules: Array + get() = emptyArray() override fun moduleDependencyComparator(): Nothing = throw UnsupportedOperationException() @@ -36,21 +38,27 @@ class EmptyModuleManager(private val project: Project) : ModuleManager() { override fun getModifiableModel(): Nothing = throw UnsupportedOperationException() - override fun getModuleGroupPath(module: Module): Array = emptyArray() + override fun getModuleGroupPath(module: Module): Array = emptyArray() - override fun setUnloadedModules(unloadedModuleNames: MutableList) { + override suspend fun setUnloadedModules(unloadedModuleNames: List) { + } + + override fun setUnloadedModulesSync(unloadedModuleNames: List) { } override fun getModuleGrouper(model: ModifiableModuleModel?): ModuleGrouper { return createGrouper(project, model) } - override fun getAllModuleDescriptions(): List = emptyList() + override val allModuleDescriptions: List + get() = emptyList() - override fun getUnloadedModuleDescriptions(): List = emptyList() + + override val unloadedModuleDescriptions: List + get() = emptyList() override fun getUnloadedModuleDescription(moduleName: String): Nothing? = null - override fun removeUnloadedModules(unloadedModules: MutableCollection) { + override fun removeUnloadedModules(unloadedModules: Collection) { } } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModulePointerManagerImpl.kt b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModulePointerManagerImpl.kt index d77fc7d7137b..06fdece02b3c 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModulePointerManagerImpl.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModulePointerManagerImpl.kt @@ -33,14 +33,12 @@ class ModulePointerManagerImpl(private val project: Project) : ModulePointerMana unregisterPointer(module) } - override fun moduleAdded(project: Project, module: Module) { - moduleAppears(module) + override fun modulesAdded(project: Project, modules: List) { + modulesAppears(modules) } override fun modulesRenamed(project: Project, modules: List, oldNameProvider: Function) { - for (module in modules) { - moduleAppears(module) - } + modulesAppears(modules) val renamedOldToNew = modules.associateBy({ oldNameProvider.`fun`(it) }, { it.name }) for (entry in oldToNewName.entries) { val newValue = renamedOldToNew.get(entry.value) @@ -95,11 +93,13 @@ class ModulePointerManagerImpl(private val project: Project) : ModulePointerMana } } - private fun moduleAppears(module: Module) { + private fun modulesAppears(modules: List) { lock.write { - unresolved.remove(module.name)?.forEach { - it.moduleAdded(module) - registerPointer(module, it) + for (module in modules) { + unresolved.remove(module.name)?.forEach { + it.moduleAdded(module) + registerPointer(module, it) + } } } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/modulePath.kt b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/modulePath.kt index f53298f8e996..369d472c82ec 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/modulePath.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/modulePath.kt @@ -1,26 +1,8 @@ -/* - * 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-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.module.impl import com.intellij.ide.highlighter.ModuleFileType -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.util.PathUtil -import com.intellij.util.io.URLUtil -import org.jdom.Element -import org.jetbrains.jps.model.serialization.JpsProjectLoader +import com.intellij.util.PathUtilRt /** * Path here must be system-independent. @@ -33,41 +15,5 @@ data class ModulePath(val path: String, val group: String?) { } fun getModuleNameByFilePath(path: String): String { - return PathUtil.getFileName(path).removeSuffix(ModuleFileType.DOT_DEFAULT_EXTENSION) -} - -internal abstract class SaveItem { - protected abstract val moduleName: String - protected abstract val moduleFilePath: String - - protected abstract val groupPathString: String? - - fun writeExternal(parentElement: Element) { - val moduleFilePath = moduleFilePath - // moduleFilePath is empty for non-persistent modules. Such modules should disappear when IDE exits, - // hence they should not be mentioned in `modules.xml`. - if (moduleFilePath.isNotEmpty()) { - val moduleElement = Element(JpsProjectLoader.MODULE_TAG) - val url = VirtualFileManager.constructUrl(URLUtil.FILE_PROTOCOL, moduleFilePath) - moduleElement.setAttribute(JpsProjectLoader.FILE_URL_ATTRIBUTE, url) - // support for older builds - moduleElement.setAttribute(JpsProjectLoader.FILE_PATH_ATTRIBUTE, moduleFilePath) - - groupPathString?.let { - moduleElement.setAttribute(JpsProjectLoader.GROUP_ATTRIBUTE, it) - } - parentElement.addContent(moduleElement) - } - } -} - -internal class ModulePathSaveItem(private val modulePath: ModulePath) : SaveItem() { - override val groupPathString: String? - get() = modulePath.group - - override val moduleFilePath: String - get() = modulePath.path - - override val moduleName: String - get() = modulePath.moduleName + return PathUtilRt.getFileName(path).removeSuffix(ModuleFileType.DOT_DEFAULT_EXTENSION) } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java index bcc4203f4953..ee7c6bf23e8e 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java @@ -49,7 +49,6 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers private final OrderRootsCache myRootsCache; - protected boolean myStartupActivityPerformed; private boolean myStateLoaded; @ApiStatus.Internal @@ -450,6 +449,12 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers } } + @Override + public @NotNull AutoCloseable withRootsChange(@NotNull RootsChangeRescanningInfo changes) { + myRootsChanged.beforeRootsChanged(); + return () -> myRootsChanged.rootsChanged(changes); + } + protected boolean isFiringEvent; private void fireBeforeRootsChanged(boolean fileTypes) { diff --git a/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerBridgeImpl.kt b/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerBridgeImpl.kt index 722a04a8d782..ac89d4c1e972 100644 --- a/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerBridgeImpl.kt +++ b/platform/projectModel-impl/src/com/intellij/workspaceModel/ide/impl/legacyBridge/module/ModuleManagerBridgeImpl.kt @@ -5,8 +5,9 @@ import com.intellij.ProjectTopics import com.intellij.ide.plugins.PluginManagerCore import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.EDT import com.intellij.openapi.application.WriteAction -import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.application.asContextElement import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.components.impl.stores.ModuleStore import com.intellij.openapi.diagnostic.debug @@ -14,6 +15,8 @@ import com.intellij.openapi.diagnostic.getOrLogException import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.module.* import com.intellij.openapi.module.impl.* +import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.progress.impl.CoreProgressManager import com.intellij.openapi.project.Project import com.intellij.openapi.project.RootsChangeRescanningInfo import com.intellij.openapi.roots.ModuleRootManager @@ -25,7 +28,6 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager import com.intellij.serviceContainer.PrecomputedExtensionModel import com.intellij.serviceContainer.precomputeExtensionModel import com.intellij.util.graph.* -import com.intellij.util.io.systemIndependentPath import com.intellij.workspaceModel.ide.* import com.intellij.workspaceModel.ide.impl.legacyBridge.module.roots.ModuleLibraryTableBridgeImpl import com.intellij.workspaceModel.ide.impl.legacyBridge.module.roots.ModuleRootComponentBridge @@ -33,22 +35,20 @@ import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge import com.intellij.workspaceModel.storage.* import com.intellij.workspaceModel.storage.bridgeEntities.api.* import com.intellij.workspaceModel.storage.url.VirtualFileUrl +import kotlinx.coroutines.* import org.jdom.Element import org.jetbrains.annotations.ApiStatus import org.jetbrains.jps.model.serialization.JpsProjectLoader import java.nio.file.Path import java.util.* -import java.util.concurrent.Callable -import java.util.concurrent.ForkJoinTask +@Suppress("OVERRIDE_DEPRECATION") @ApiStatus.Internal abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleManagerEx(), Disposable { protected val unloadedModules: MutableMap = LinkedHashMap() override fun dispose() { - modules().forEach { - Disposer.dispose(it) - } + modules().forEach(Disposer::dispose) } protected fun modules(): Sequence { @@ -80,7 +80,7 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan val entityStore = WorkspaceModel.getInstance(project).entityStorage - fun loadModules(entities: Sequence) { + suspend fun loadModules(entities: Sequence) { val unloadedModuleNames = UnloadedModulesListStorage.getInstance(project).unloadedModuleNames val (unloadedEntities, loadedEntities) = entities.partition { it.name in unloadedModuleNames } LOG.debug { "Loading modules for ${loadedEntities.size} entities" } @@ -88,26 +88,27 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan val precomputedExtensionModel = precomputeExtensionModel() val tasks = loadedEntities.map { moduleEntity -> - ForkJoinTask.adapt(Callable { + project.coroutineScope.async { runCatching { val module = createModuleInstance(moduleEntity, entityStore, null, false, precomputedExtensionModel) moduleEntity to module }.getOrLogException(LOG) - }) + } } - ForkJoinTask.invokeAll(tasks) + val result = tasks.awaitAll() + UnloadedModuleDescriptionBridge.createDescriptions(unloadedEntities).associateByTo(unloadedModules) { it.name } - val modules = HashSet() + val modules = LinkedHashSet(result.size) WorkspaceModel.getInstance(project).updateProjectModelSilent { builder -> val moduleMap = builder.mutableModuleMap - for (task in tasks) { - val (entity, module) = task.rawResult ?: continue - modules += module + for (item in result) { + val (entity, module) = item ?: continue + modules.add(module) moduleMap.addMapping(entity, module) - (ModuleRootComponentBridge.getInstance( - module).getModuleLibraryTable() as ModuleLibraryTableBridgeImpl).registerModuleLibraryInstances(builder) + (ModuleRootComponentBridge.getInstance(module).getModuleLibraryTable() as ModuleLibraryTableBridgeImpl) + .registerModuleLibraryInstances(builder) } } // Facets that are loaded from the cache do not generate "EntityAdded" event and aren't initialized @@ -115,7 +116,7 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan // // Possible issue - if we'll initialize facets here and after that we'll get "EntityAdded" event, the facet will be initialized twice // But 1. That seems impossible as we don't create facets before the modules are loaded 2. I hope that facets initialization is idempotent - modules.forEach { module -> module.initFacets() } + modules.forEach(ModuleBridge::initFacets) } override fun unloadNewlyAddedModulesIfPossible(storage: EntityStorage) { @@ -133,7 +134,7 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan override fun newModule(filePath: String, moduleTypeId: String): Module { incModificationCount() - val modifiableModel = modifiableModel + val modifiableModel = getModifiableModel() val module = modifiableModel.newModule(filePath, moduleTypeId) modifiableModel.commit() return module @@ -141,7 +142,7 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan override fun newNonPersistentModule(moduleName: String, id: String): Module { incModificationCount() - val modifiableModel = modifiableModel + val modifiableModel = getModifiableModel() val module = modifiableModel.newNonPersistentModule(moduleName, id) modifiableModel.commit() return module @@ -149,7 +150,8 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan override fun getModuleDependentModules(module: Module): List = modules.filter { isModuleDependent(it, module) } - override fun getUnloadedModuleDescriptions(): Collection = unloadedModules.values + override val unloadedModuleDescriptions: Collection + get() = unloadedModules.values override fun getFailedModulePaths(): Collection = emptyList() @@ -157,20 +159,22 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan override fun isModuleDependent(module: Module, onModule: Module): Boolean = ModuleRootManager.getInstance(module).isDependsOn(onModule) - override fun getAllModuleDescriptions(): Collection { - return (modules().map { LoadedModuleDescriptionImpl(it) } + unloadedModuleDescriptions).toList() - } + override val allModuleDescriptions: Collection + get() = (modules().map { LoadedModuleDescriptionImpl(it) } + unloadedModuleDescriptions).toList() override fun getModuleGroupPath(module: Module): Array? = getModuleGroupPath(module, entityStore) override fun getModuleGrouper(model: ModifiableModuleModel?): ModuleGrouper = createGrouper(project, model) override fun loadModule(file: Path): Module { - return loadModule(file.systemIndependentPath) + val model = getModifiableModel() + val module = model.loadModule(file) + model.commit() + return module } override fun loadModule(filePath: String): Module { - val model = modifiableModel + val model = getModifiableModel() val module = model.loadModule(filePath) model.commit() return module @@ -182,7 +186,8 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan modules(storage).toList().toTypedArray() } - override fun getModules(): Array = entityStore.cachedValue(modulesArrayValue) + override val modules: Array + get() = entityStore.cachedValue(modulesArrayValue) private val sortedModulesValue = CachedValue { storage -> val allModules = modules(storage).toList().toTypedArray() @@ -190,7 +195,8 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan allModules } - override fun getSortedModules(): Array = entityStore.cachedValue(sortedModulesValue) + override val sortedModules: Array + get() = entityStore.cachedValue(sortedModulesValue) override fun findModuleByName(name: String): Module? { val entity = entityStore.current.resolve(ModuleId(name)) ?: return null @@ -198,13 +204,14 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan } override fun disposeModule(module: Module) = ApplicationManager.getApplication().runWriteAction { - val modifiableModel = modifiableModel + val modifiableModel = getModifiableModel() modifiableModel.disposeModule(module) modifiableModel.commit() } - override fun setUnloadedModules(unloadedModuleNames: List) { - if (unloadedModules.keys == unloadedModuleNames) { // optimization + override suspend fun setUnloadedModules(unloadedModuleNames: List) { + // optimization + if (unloadedModules.keys == unloadedModuleNames) { return } @@ -238,38 +245,60 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan project.save() } - runWriteAction { - ProjectRootManagerEx.getInstanceEx(project).makeRootsChange({ - for ((moduleEntity, module) in modulesToUnload) { - fireBeforeModuleRemoved(module) + withContext(Dispatchers.EDT) { + ApplicationManager.getApplication().runWriteAction { + ProjectRootManagerEx.getInstanceEx(project).withRootsChange(RootsChangeRescanningInfo.NO_RESCAN_NEEDED).use { + for ((moduleEntity, module) in modulesToUnload) { + fireBeforeModuleRemoved(module) - val description = LoadedModuleDescriptionImpl(module) - val modulePath = getModulePath(module, entityStore) - val pointerManager = VirtualFilePointerManager.getInstance() - val contentRoots = ModuleRootManager.getInstance(module).contentRootUrls.map { url -> - pointerManager.create(url, this, null) + val description = LoadedModuleDescriptionImpl(module) + val modulePath = getModulePath(module, entityStore) + val pointerManager = VirtualFilePointerManager.getInstance() + val contentRoots = ModuleRootManager.getInstance( + module).contentRootUrls.map { url -> + pointerManager.create(url, this@ModuleManagerBridgeImpl, null) + } + val unloadedModuleDescription = UnloadedModuleDescriptionImpl( + modulePath, description.dependencyModuleNames, contentRoots) + unloadedModules[module.name] = unloadedModuleDescription + WorkspaceModel.getInstance(project).updateProjectModelSilent { + it.mutableModuleMap.removeMapping(moduleEntity) + } + fireEventAndDisposeModule(module) } - val unloadedModuleDescription = UnloadedModuleDescriptionImpl(modulePath, description.dependencyModuleNames, contentRoots) - unloadedModules[module.name] = unloadedModuleDescription - WorkspaceModel.getInstance(project).updateProjectModelSilent { - it.mutableModuleMap.removeMapping(moduleEntity) - } - fireEventAndDisposeModule(module) - } - // Remove Facet bridges to recreate them. String constant is taken from - // com.intellij.workspaceModel.ide.impl.legacyBridge.facet.FacetModelBridge.FACET_BRIDGE_MAPPING_ID - WorkspaceModel.getInstance(project).updateProjectModelSilent { builder -> - moduleEntitiesToLoad.flatMap { it.facets }.forEach { - builder.getMutableExternalMapping("intellij.facets.bridge").removeMapping(it) + // Remove Facet bridges to recreate them. String constant is taken from + // com.intellij.workspaceModel.ide.impl.legacyBridge.facet.FacetModelBridge.FACET_BRIDGE_MAPPING_ID + WorkspaceModel.getInstance( + project).updateProjectModelSilent { builder -> + moduleEntitiesToLoad.flatMap { it.facets }.forEach { + builder.getMutableExternalMapping( + "intellij.facets.bridge").removeMapping(it) + } + } + // todo why we load modules in a write action + runBlocking { + loadModules(moduleEntitiesToLoad.asSequence()) } } - loadModules(moduleEntitiesToLoad.asSequence()) - }, RootsChangeRescanningInfo.NO_RESCAN_NEEDED) + } } } - override fun removeUnloadedModules(unloadedModules: MutableCollection) { + override fun setUnloadedModulesSync(unloadedModuleNames: List) { + if (!ApplicationManager.getApplication().isDispatchThread) { + return runBlocking(CoreProgressManager.getCurrentThreadProgressModality().asContextElement()) { setUnloadedModules(unloadedModuleNames) } + } + + ProgressManager.getInstance().runProcessWithProgressSynchronously(Runnable { + val modalityState = CoreProgressManager.getCurrentThreadProgressModality() + runBlocking(modalityState.asContextElement()) { + setUnloadedModules(unloadedModuleNames) + } + }, "", true, project) + } + + override fun removeUnloadedModules(unloadedModules: Collection) { ApplicationManager.getApplication().assertWriteAccessAllowed() unloadedModules.forEach { this.unloadedModules.remove(it.name) } @@ -437,8 +466,8 @@ abstract class ModuleManagerBridgeImpl(private val project: Project) : ModuleMan else { VirtualFileManager.extractPath(fileUrlValue) } - paths.add(ModulePath(FileUtilRt.toSystemIndependentName(Objects.requireNonNull(filepath)), - moduleElement.getAttributeValue(JpsProjectLoader.GROUP_ATTRIBUTE))) + paths.add(ModulePath(path = FileUtilRt.toSystemIndependentName(filepath!!), + group = moduleElement.getAttributeValue(JpsProjectLoader.GROUP_ATTRIBUTE))) } return paths } diff --git a/platform/testFramework/src/com/intellij/module/moduleGroupTests.kt b/platform/testFramework/src/com/intellij/module/moduleGroupTests.kt index 77e3d22c872c..7243ad2b4e1b 100644 --- a/platform/testFramework/src/com/intellij/module/moduleGroupTests.kt +++ b/platform/testFramework/src/com/intellij/module/moduleGroupTests.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 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-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.module import com.intellij.openapi.application.runWriteAction @@ -39,7 +25,7 @@ fun runWithQualifiedModuleNamesEnabled(action: () -> T): T { } fun renameModule(module: Module, newName: String) { - val model = ModuleManager.getInstance(module.project).modifiableModel + val model = ModuleManager.getInstance(module.project).getModifiableModel() model.renameModule(module, newName) runWriteAction { model.commit() } } \ No newline at end of file diff --git a/platform/testFramework/src/com/intellij/project/TestProjectManager.kt b/platform/testFramework/src/com/intellij/project/TestProjectManager.kt index 41fcc0b3b1dc..e65176527485 100644 --- a/platform/testFramework/src/com/intellij/project/TestProjectManager.kt +++ b/platform/testFramework/src/com/intellij/project/TestProjectManager.kt @@ -8,6 +8,7 @@ import com.intellij.ide.impl.OpenProjectTask import com.intellij.ide.impl.ProjectUtil import com.intellij.ide.impl.runUnderModalProgressIfIsEdt import com.intellij.ide.startup.StartupManagerEx +import com.intellij.ide.startup.impl.StartupManagerImpl import com.intellij.openapi.Disposable import com.intellij.openapi.application.AccessToken import com.intellij.openapi.application.ApplicationManager @@ -17,12 +18,12 @@ import com.intellij.openapi.command.impl.UndoManagerImpl import com.intellij.openapi.command.undo.UndoManager import com.intellij.openapi.components.StorageScheme import com.intellij.openapi.progress.ProcessCanceledException -import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project import com.intellij.openapi.project.ex.ProjectEx import com.intellij.openapi.project.impl.ProjectImpl import com.intellij.openapi.project.impl.ProjectManagerImpl -import com.intellij.openapi.project.impl.runStartupActivities +import com.intellij.openapi.project.impl.runInitProjectActivities +import com.intellij.openapi.startup.StartupManager import com.intellij.openapi.util.Disposer import com.intellij.testFramework.LeakHunter import com.intellij.testFramework.TestApplicationManager.Companion.publishHeapDump @@ -31,7 +32,6 @@ import com.intellij.util.containers.UnsafeWeakList import com.intellij.util.ref.GCUtil import kotlinx.coroutines.runBlocking import org.jetbrains.annotations.ApiStatus -import org.jetbrains.annotations.NotNull import java.nio.file.Path import java.util.* import java.util.concurrent.TimeUnit @@ -118,13 +118,12 @@ open class TestProjectManager : ProjectManagerImpl() { } val app = ApplicationManager.getApplication() - try { runUnderModalProgressIfIsEdt { - runStartupActivities(project = project, - indicator = ProgressManager.getInstance().progressIndicator, - runStartUpActivities = isRunStartUpActivitiesEnabled(project), - waitEdtActivity = null) + runInitProjectActivities(project = project) + if (isRunStartUpActivitiesEnabled(project)) { + (StartupManager.getInstance(project) as StartupManagerImpl).runStartupActivities() + } } } catch (e: ProcessCanceledException) { @@ -142,7 +141,7 @@ open class TestProjectManager : ProjectManagerImpl() { return project } - private fun trackProject(project: @NotNull Project) { + private fun trackProject(project: Project) { if (isTracking) { synchronized(this) { if (isTracking) { diff --git a/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt b/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt index e7e6ba93312d..d7caf657d1e3 100644 --- a/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt +++ b/platform/testFramework/src/com/intellij/testFramework/rules/ProjectModelRule.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.testFramework.rules import com.intellij.facet.Facet @@ -173,7 +173,7 @@ open class ProjectModelRule(private val forceEnableWorkspaceModel: Boolean = fal } fun renameModule(module: Module, newName: String) { - val model = runReadAction { moduleManager.modifiableModel } + val model = runReadAction { moduleManager.getModifiableModel() } model.renameModule(module, newName) runWriteActionAndWait { model.commit() } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ModuleDefaultVcsRootPolicy.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ModuleDefaultVcsRootPolicy.java index b55a4024ca3c..5bcbe4aab40f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ModuleDefaultVcsRootPolicy.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ModuleDefaultVcsRootPolicy.java @@ -1,5 +1,4 @@ -// Copyright 2000-2020 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. - +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.vcs.impl; import com.intellij.ProjectTopics; @@ -22,10 +21,11 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; -public class ModuleDefaultVcsRootPolicy extends DefaultVcsRootPolicy { - public ModuleDefaultVcsRootPolicy(@NotNull Project project) { +final class ModuleDefaultVcsRootPolicy extends DefaultVcsRootPolicy { + ModuleDefaultVcsRootPolicy(@NotNull Project project) { super(project); MyModulesListener listener = new MyModulesListener(); @@ -66,14 +66,14 @@ public class ModuleDefaultVcsRootPolicy extends DefaultVcsRootPolicy { return result; } - private class MyModulesListener implements ModuleRootListener, ModuleListener, AdditionalLibraryRootsListener { + private final class MyModulesListener implements ModuleRootListener, ModuleListener, AdditionalLibraryRootsListener { @Override public void rootsChanged(@NotNull ModuleRootEvent event) { scheduleMappedRootsUpdate(); } @Override - public void moduleAdded(@NotNull Project project, @NotNull Module module) { + public void modulesAdded(@NotNull Project project, @NotNull List modules) { scheduleMappedRootsUpdate(); } diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/LibraryPropertiesTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/LibraryPropertiesTest.kt index 14bde50bb686..334b2c4ba7d9 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/LibraryPropertiesTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/LibraryPropertiesTest.kt @@ -82,7 +82,7 @@ class LibraryPropertiesTest { val elementAsString = "" val moduleFile = File(project.basePath, "$moduleName.iml") - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModifiableRootModelBridgeTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModifiableRootModelBridgeTest.kt index 4f64e579daa0..4ec55fe9e977 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModifiableRootModelBridgeTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModifiableRootModelBridgeTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.workspaceModel.ide import com.intellij.openapi.application.runWriteActionAndWait @@ -50,7 +50,7 @@ class ModifiableRootModelBridgeTest { @Test(expected = Test.None::class) fun `getting module root model from modifiable module`() { runWriteActionAndWait { - val moduleModifiableModel = ModuleManager.getInstance(projectModel.project).modifiableModel + val moduleModifiableModel = ModuleManager.getInstance(projectModel.project).getModifiableModel() val newModule = moduleModifiableModel.newModule(projectModel.projectRootDir.resolve("myModule/myModule.iml"), EmptyModuleType.EMPTY_MODULE) as ModuleBridge @@ -68,7 +68,7 @@ class ModifiableRootModelBridgeTest { @Test(expected = Test.None::class) fun `get modifiable models of renamed module`() { runWriteActionAndWait { - val moduleModifiableModel = ModuleManager.getInstance(projectModel.project).modifiableModel + val moduleModifiableModel = ModuleManager.getInstance(projectModel.project).getModifiableModel() val newModule = moduleModifiableModel.newModule(projectModel.projectRootDir.resolve("myModule/myModule.iml"), EmptyModuleType.EMPTY_MODULE) as ModuleBridge moduleModifiableModel.commit() diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleBridgesTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleBridgesTest.kt index ec853b9e7349..322f06018337 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleBridgesTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleBridgesTest.kt @@ -82,7 +82,7 @@ class ModuleBridgesTest { WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) - val module = moduleManager.modifiableModel.let { + val module = moduleManager.getModifiableModel().let { val m = it.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) as ModuleBridge it.commit() m @@ -103,7 +103,7 @@ class ModuleBridgesTest { arrayOf(contentRootUrl.url) ) - moduleManager.modifiableModel.let { + moduleManager.getModifiableModel().let { it.disposeModule(module) it.commit() } @@ -115,7 +115,7 @@ class ModuleBridgesTest { WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) - val modulesModifiableModel = moduleManager.modifiableModel + val modulesModifiableModel = moduleManager.getModifiableModel() try { val m = modulesModifiableModel.newModule(File(project.basePath, "xxx.iml").path, ModuleType.EMPTY.id) as ModuleBridge val rootModel = m.rootManager.modifiableModel @@ -143,7 +143,7 @@ class ModuleBridgesTest { runBlocking { val module = withContext(Dispatchers.EDT) { runWriteAction { - val model = moduleManager.modifiableModel + val model = moduleManager.getModifiableModel() val module = model.newModule(oldNameFile.path, ModuleType.EMPTY.id) model.commit() module @@ -159,7 +159,7 @@ class ModuleBridgesTest { withContext(Dispatchers.EDT) { ApplicationManager.getApplication().runWriteAction { - val model = moduleManager.modifiableModel + val model = moduleManager.getModifiableModel() assertSame(module, model.findModuleByName(oldModuleName)) assertNull(model.getModuleToBeRenamed(oldModuleName)) @@ -212,7 +212,7 @@ class ModuleBridgesTest { val (antModule, mavenModule) = withContext(Dispatchers.EDT) { runWriteAction { - val model = moduleManager.modifiableModel + val model = moduleManager.getModifiableModel() val antModule = model.newModule(antModuleFile.path, ModuleType.EMPTY.id) val mavenModule = model.newModule(mavenModuleFile.path, ModuleType.EMPTY.id) model.commit() @@ -232,7 +232,7 @@ class ModuleBridgesTest { withContext(Dispatchers.EDT) { ApplicationManager.getApplication().runWriteAction { - val model = moduleManager.modifiableModel + val model = moduleManager.getModifiableModel() model.renameModule(antModule, gradleModuleName) model.commit() } @@ -287,7 +287,7 @@ class ModuleBridgesTest { WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) - val module = moduleManager.modifiableModel.let { + val module = moduleManager.getModifiableModel().let { val m = it.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) as ModuleBridge it.commit() m @@ -314,7 +314,7 @@ class ModuleBridgesTest { WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) - val module = moduleManager.modifiableModel.let { + val module = moduleManager.getModifiableModel().let { val m = it.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) as ModuleBridge it.commit() m @@ -631,7 +631,7 @@ class ModuleBridgesTest { val module = withContext(Dispatchers.EDT) { runWriteAction { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -674,7 +674,7 @@ class ModuleBridgesTest { val antLibraryFolder = "ant-lib" val moduleFile = File(project.basePath, "$moduleName.iml") - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -705,7 +705,7 @@ class ModuleBridgesTest { fun `test disposed module doesn't appear in rootsChanged`() = WriteCommandAction.runWriteCommandAction(project) { val moduleName = "build" val moduleFile = File(project.basePath, "$moduleName.iml") - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -726,7 +726,7 @@ class ModuleBridgesTest { WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) as ModuleManagerBridgeImpl - moduleManager.modifiableModel.let { modifiableModel -> + moduleManager.getModifiableModel().let { modifiableModel -> modifiableModel.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) as ModuleBridge modifiableModel.commit() } @@ -754,7 +754,7 @@ class ModuleBridgesTest { fun `remove module without removing module library`() = WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) as ModuleManagerBridgeImpl - val module = moduleManager.modifiableModel.let { modifiableModel -> + val module = moduleManager.getModifiableModel().let { modifiableModel -> val module = modifiableModel.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) modifiableModel.commit() module as ModuleBridge @@ -785,13 +785,13 @@ class ModuleBridgesTest { fun `readd module`() = WriteCommandAction.runWriteCommandAction(project) { val moduleManager = ModuleManager.getInstance(project) - val module = moduleManager.modifiableModel.let { modifiableModel -> + val module = moduleManager.getModifiableModel().let { modifiableModel -> val module = modifiableModel.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) modifiableModel.commit() module as ModuleBridge } - val newModule = moduleManager.modifiableModel.let { modifiableModel -> + val newModule = moduleManager.getModifiableModel().let { modifiableModel -> modifiableModel.disposeModule(module) val newModule = modifiableModel.newModule(File(project.basePath, "xxx.iml").path, EmptyModuleType.getInstance().id) modifiableModel.commit() diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleLibraryBridgeTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleLibraryBridgeTest.kt index 63ab83476a5a..4b1241967c15 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleLibraryBridgeTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ModuleLibraryBridgeTest.kt @@ -56,7 +56,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val module = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -102,7 +102,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val module = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -166,7 +166,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val rootModel = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -257,7 +257,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val module = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -329,7 +329,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val moduleRootManager = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -366,7 +366,7 @@ class ModuleLibraryBridgeTest { val gradleLibraryName = "gradle-lib" val moduleFile = File(project.basePath, "$moduleName.iml") - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -412,7 +412,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val module = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module @@ -453,7 +453,7 @@ class ModuleLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val module = WriteCommandAction.writeCommandAction(project).compute { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ProjectLibraryBridgeTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ProjectLibraryBridgeTest.kt index 0421f3988f1b..a7c852cd69df 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ProjectLibraryBridgeTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/ProjectLibraryBridgeTest.kt @@ -335,7 +335,7 @@ class ProjectLibraryBridgeTest { assertTrue(iprFile.readText().contains(antLibraryName)) WriteCommandAction.runWriteCommandAction(project) { - val module = ModuleManager.getInstance(project).modifiableModel.let { + val module = ModuleManager.getInstance(project).getModifiableModel().let { val module = it.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge it.commit() module @@ -386,7 +386,7 @@ class ProjectLibraryBridgeTest { val moduleFile = File(project.basePath, "$moduleName.iml") val library = runBlocking { createProjectLibrary(antLibraryName, withRoots = false) } WriteCommandAction.runWriteCommandAction(project) { - val module = ModuleManager.getInstance(project).modifiableModel.let { moduleModel -> + val module = ModuleManager.getInstance(project).getModifiableModel().let { moduleModel -> val module = moduleModel.newModule(moduleFile.path, EmptyModuleType.getInstance().id) as ModuleBridge moduleModel.commit() module diff --git a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt index 81ea95a19267..5ba383949bf0 100644 --- a/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt +++ b/platform/workspaceModel/jps/tests/testSrc/com/intellij/workspaceModel/ide/WorkspaceModelPerformanceTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.workspaceModel.ide import com.intellij.openapi.application.ex.ApplicationManagerEx @@ -127,7 +127,7 @@ class WorkspaceModelPerformanceTest(private val modulesCount: Int) { private fun hundredModulesRemove(modules: MutableList, moduleManager: ModuleManager) { modules.forEach { - val modifiableModel = moduleManager.modifiableModel + val modifiableModel = moduleManager.getModifiableModel() modifiableModel.disposeModule(it) modifiableModel.commit() } @@ -178,7 +178,7 @@ class WorkspaceModelPerformanceTest(private val modulesCount: Int) { private fun hundredModulesCreation(moduleManager: ModuleManager, modules: MutableList) { (1..100).forEach { - val modifiableModel = moduleManager.modifiableModel + val modifiableModel = moduleManager.getModifiableModel() modules.add(modifiableModel.newModule(File(project.basePath, "$TEST_MODULE_PREFIX$it.iml").path, EmptyModuleType.getInstance().id)) modifiableModel.commit() } diff --git a/plugins/gradle/java/testSources/importing/GradleMiscImportingTest.java b/plugins/gradle/java/testSources/importing/GradleMiscImportingTest.java index 3d0a1b1cc98c..3482f3149c2b 100644 --- a/plugins/gradle/java/testSources/importing/GradleMiscImportingTest.java +++ b/plugins/gradle/java/testSources/importing/GradleMiscImportingTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.plugins.gradle.importing; import com.intellij.ide.highlighter.ModuleFileType; @@ -173,7 +173,7 @@ public class GradleMiscImportingTest extends GradleJavaImportingTestCase { ); assertModules("project", "project.main", "project.test"); - edt(() -> ModuleManager.getInstance(myProject).setUnloadedModules(Collections.singletonList("project.main"))); + edt(() -> ModuleManager.getInstance(myProject).setUnloadedModulesSync(Collections.singletonList("project.main"))); assertModules("project", "project.test"); importProject(); diff --git a/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/testFramework/ProjectBuilder.kt b/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/testFramework/ProjectBuilder.kt index bbbf89ebce5f..75ad68459c9b 100644 --- a/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/testFramework/ProjectBuilder.kt +++ b/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/testFramework/ProjectBuilder.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.testFramework @@ -262,7 +262,7 @@ class ModuleDescription(val moduleName: String) { val moduleVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByNioFile(modulePath) ?: error("unable to find ${modulePath}") runWriteAction { val moduleManager = ModuleManager.getInstance(project) - val module = with(moduleManager.modifiableModel) { + val module = with(moduleManager.getModifiableModel()) { val imlPath = modulePath.resolve("$moduleName${ModuleFileType.DOT_DEFAULT_EXTENSION}") val module = newModule(imlPath, ModuleTypeId.JAVA_MODULE) PsiTestUtil.addSourceRoot(module, moduleVirtualFile.findFileByRelativePath(src) ?: error("no '$src' in $this")) diff --git a/plugins/kotlin/project-wizard/idea/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt b/plugins/kotlin/project-wizard/idea/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt index 8c00906d1db6..afd74b3ca8d5 100644 --- a/plugins/kotlin/project-wizard/idea/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt +++ b/plugins/kotlin/project-wizard/idea/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.tools.projectWizard.wizard import com.intellij.ide.RecentProjectsManager @@ -107,7 +107,7 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() { runWriteAction { wizard.jdk?.let { jdk -> JavaSdkUtil.applyJdkToProject(project, jdk) } } - val modulesModel = model ?: ModuleManager.getInstance(project).modifiableModel + val modulesModel = model ?: ModuleManager.getInstance(project).getModifiableModel() val success = wizard.apply( services = buildList { +IdeaServices.createScopeDependent(project) diff --git a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt index 103029236a4b..b43726c6db91 100644 --- a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt +++ b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinMultiFileTestCase.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.test @@ -63,7 +63,7 @@ abstract class KotlinMultiFileTestCase : MultiFileTestCase() { override fun prepareProject(rootDir: VirtualFile) { if (isMultiModule) { - val model = ModuleManager.getInstance(project).modifiableModel + val model = ModuleManager.getInstance(project).getModifiableModel() VfsUtilCore.visitChildrenRecursively( rootDir, diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java index 4f2b2fcafd83..cd9b00843727 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java @@ -583,9 +583,13 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent private void projectClosed() { initLock.lock(); try { - if (!isInitialized.getAndSet(false)) return; + if (!isInitialized.getAndSet(false)) { + return; + } - Disposer.dispose(myImportingQueue); + if (myImportingQueue != null) { + Disposer.dispose(myImportingQueue); + } myWatcher.stop(); diff --git a/plugins/package-search/src/com/jetbrains/packagesearch/intellij/plugin/util/ProjectExtensions.kt b/plugins/package-search/src/com/jetbrains/packagesearch/intellij/plugin/util/ProjectExtensions.kt index 8bca8f3b1678..0732a1f3104b 100644 --- a/plugins/package-search/src/com/jetbrains/packagesearch/intellij/plugin/util/ProjectExtensions.kt +++ b/plugins/package-search/src/com/jetbrains/packagesearch/intellij/plugin/util/ProjectExtensions.kt @@ -92,7 +92,7 @@ internal val Project.trustedProjectFlow: Flow internal val Project.nativeModulesFlow: Flow> get() = messageBusFlow(ProjectTopics.MODULES, { getNativeModules() }) { object : ModuleListener { - override fun moduleAdded(project: Project, module: Module) { + override fun modulesAdded(project: Project, modules: List) { trySend(getNativeModules()) } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java index f91aaa2b2203..3ce9ca0f55cf 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java @@ -81,8 +81,7 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher getFileDataKey() { + public @NotNull Key getFileDataKey() { return KEY; } @@ -92,19 +91,16 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher orderEntries = ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(file); for (OrderEntry orderEntry : orderEntries) { @@ -128,8 +123,7 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher moduleSdks = getPythonModuleSdks(project); final boolean needToReparseOpenFiles = ContainerUtil.exists(moduleSdks.entrySet(), entry -> { final Module module = entry.getKey(); @@ -224,10 +218,11 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher getPythonModuleSdks(@NotNull Project project) { - final ModuleManager moduleManager = ModuleManager.getInstance(project); - if (moduleManager == null) return Collections.emptyMap(); + private static @NotNull Map<@NotNull Module, @NotNull Sdk> getPythonModuleSdks(@NotNull Project project) { + ModuleManager moduleManager = ModuleManager.Companion.getInstanceIfDefined(project); + if (moduleManager == null) { + return Collections.emptyMap(); + } final Map result = new LinkedHashMap<>(); for (Module module : moduleManager.getModules()) { @@ -284,8 +279,7 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher pythonModuleSdks) { + private static @NotNull LanguageLevel guessLanguageLevelWithCaching(@NotNull Project project, @NotNull Collection pythonModuleSdks) { LanguageLevel languageLevel = LanguageLevel.fromPythonVersion(project.getUserData(KEY)); if (languageLevel == null) { languageLevel = guessLanguageLevel(pythonModuleSdks); @@ -299,8 +293,7 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher pythonModuleSdks) { + private static @NotNull LanguageLevel guessLanguageLevel(@NotNull Collection pythonModuleSdks) { LanguageLevel maxLevel = null; for (Sdk sdk : pythonModuleSdks) { final LanguageLevel level = PythonRuntimeService.getInstance().getLanguageLevelForSdk(sdk); @@ -319,8 +312,7 @@ public final class PythonLanguageLevelPusher implements FilePropertyPusher moduleSdks; private final SimpleMessageBusConnection connection;