diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt b/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt index 484abb50f38b..c0bb878413d3 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt @@ -1185,15 +1185,22 @@ private fun doCheckExtensionsCanUnloadWithoutRestart(extensions: Map(epName) if (ep != null) { if (!ep.isDynamic) { - if (optionalDependencyPluginId != null) { - return "Plugin ${baseDescriptor?.pluginId} is not unload-safe because of use of non-dynamic EP $epName in plugin $optionalDependencyPluginId that optionally depends on it" - } - else { - return "Plugin ${descriptor.pluginId ?: baseDescriptor?.pluginId} is not unload-safe because of extension to non-dynamic EP $epName" - } + return getNonDynamicUnloadError(epName, baseDescriptor, descriptor, optionalDependencyPluginId) } continue } + if (anyModule == null) { + val corePlugin = PluginManagerCore.getPlugin(PluginManagerCore.CORE_ID) + if (corePlugin != null) { + val coreEP = findPluginExtensionPoint(corePlugin as IdeaPluginDescriptorImpl, epName) + if (coreEP != null) { + if (!coreEP.isDynamic) { + return getNonDynamicUnloadError(epName, baseDescriptor, descriptor, optionalDependencyPluginId) + } + continue + } + } + } val contextEP = context.asSequence().mapNotNull { contextPlugin -> findPluginExtensionPoint(contextPlugin, epName) }.firstOrNull() if (contextEP != null) { @@ -1208,6 +1215,18 @@ private fun doCheckExtensionsCanUnloadWithoutRestart(extensions: Map? { return findContainerExtensionPoint(pluginDescriptor.app, epName) ?: findContainerExtensionPoint(pluginDescriptor.project, epName) diff --git a/platform/platform-tests/testSrc/com/intellij/ide/plugins/DynamicPluginsTest.kt b/platform/platform-tests/testSrc/com/intellij/ide/plugins/DynamicPluginsTest.kt index f5ab2c3ec8e1..69c2684cfce2 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/plugins/DynamicPluginsTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/ide/plugins/DynamicPluginsTest.kt @@ -22,8 +22,11 @@ import com.intellij.openapi.components.* import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Editor import com.intellij.openapi.extensions.PluginId +import com.intellij.openapi.module.ModuleConfigurationEditor import com.intellij.openapi.options.Configurable import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationEditorProvider +import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState import com.intellij.openapi.startup.StartupActivity import com.intellij.openapi.util.Disposer import com.intellij.psi.PsiFile @@ -470,14 +473,23 @@ class DynamicPluginsTest { DynamicPlugins::class.java.classLoader) try { assertThat(checked.get()).isEqualTo(1) - assertThat(Configurable.PROJECT_CONFIGURABLE.getExtensions(project).any { it.instanceClass == MyConfigurable::class.java.name }).isTrue() + assertThat( + Configurable.PROJECT_CONFIGURABLE.getExtensions(project).any { it.instanceClass == MyConfigurable::class.java.name }).isTrue() } finally { Disposer.dispose(disposable) Disposer.dispose(listenerDisposable) } assertThat(checked.get()).isEqualTo(2) - assertThat(Configurable.PROJECT_CONFIGURABLE.getExtensions(project).any { it.instanceClass == MyConfigurable::class.java.name }).isFalse() + assertThat( + Configurable.PROJECT_CONFIGURABLE.getExtensions(project).any { it.instanceClass == MyConfigurable::class.java.name }).isFalse() + } + + @Test + fun unloadModuleEP() { + val disposable = loadExtensionWithText( + """""") + Disposer.dispose(disposable) } @Test @@ -699,3 +711,9 @@ private class MyRunnable : Runnable { override fun run() { } } + +private class MyModuleConfigurationEditorProvider : ModuleConfigurationEditorProvider { + override fun createEditors(state: ModuleConfigurationState?): Array { + return arrayOf() + } +}