diff --git a/java/idea-ui/testSrc/com/intellij/facet/FacetTestCase.java b/java/idea-ui/testSrc/com/intellij/facet/FacetTestCase.java
index ead801ae81be..6d9c321ae7cb 100644
--- a/java/idea-ui/testSrc/com/intellij/facet/FacetTestCase.java
+++ b/java/idea-ui/testSrc/com/intellij/facet/FacetTestCase.java
@@ -6,6 +6,8 @@ import com.intellij.facet.mock.MockFacetConfiguration;
import com.intellij.facet.mock.MockFacetType;
import com.intellij.facet.mock.MockSubFacetType;
import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.roots.ProjectModelExternalSource;
import com.intellij.testFramework.HeavyPlatformTestCase;
import org.jetbrains.annotations.Nullable;
@@ -32,12 +34,14 @@ public abstract class FacetTestCase extends HeavyPlatformTestCase {
}
protected void removeAllFacets() {
- final FacetManager manager = getFacetManager();
- final ModifiableFacetModel model = manager.createModifiableModel();
- for (Facet facet : manager.getAllFacets()) {
- model.removeFacet(facet);
+ for (Module module : ModuleManager.getInstance(myProject).getModules()) {
+ FacetManager manager = FacetManager.getInstance(module);
+ ModifiableFacetModel model = manager.createModifiableModel();
+ for (Facet> facet : manager.getAllFacets()) {
+ model.removeFacet(facet);
+ }
+ commit(model);
}
- commit(model);
}
protected FacetManager getFacetManager() {
diff --git a/java/idea-ui/testSrc/com/intellij/facet/FacetTypeUnloadingTest.kt b/java/idea-ui/testSrc/com/intellij/facet/FacetTypeUnloadingTest.kt
new file mode 100644
index 000000000000..08b035cab51b
--- /dev/null
+++ b/java/idea-ui/testSrc/com/intellij/facet/FacetTypeUnloadingTest.kt
@@ -0,0 +1,132 @@
+// 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.
+package com.intellij.facet
+
+import com.intellij.facet.impl.invalid.InvalidFacetManager
+import com.intellij.facet.mock.MockFacet
+import com.intellij.facet.mock.MockFacetConfiguration
+import com.intellij.facet.mock.MockFacetType
+import com.intellij.facet.mock.MockSubFacetType
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.JDOMUtil
+import com.intellij.testFramework.HeavyPlatformTestCase
+
+class FacetTypeUnloadingTest : HeavyPlatformTestCase() {
+ fun `test unload and load facet`() {
+ val facetManager = FacetManager.getInstance(module)
+ runWithRegisteredFacetTypes(MockFacetType()) {
+ runWriteAction {
+ val configuration = MockFacetConfiguration().apply {
+ data = "my data"
+ }
+ val model = facetManager.createModifiableModel()
+ model.addFacet(MockFacet(module, "mock", configuration))
+ model.commit()
+ }
+ assertEquals("mock", facetManager.getFacetsByType(MockFacetType.ID).single().name)
+ }
+
+ assertTrue(facetManager.getFacetsByType(MockFacetType.ID).isEmpty())
+ val invalidFacet = InvalidFacetManager.getInstance(myProject).invalidFacets.single()
+ assertEquals("mock", invalidFacet.name)
+ assertEquals("", JDOMUtil.write(invalidFacet.configuration.facetState.configuration))
+
+ registerFacetType(MockFacetType(), testRootDisposable)
+ assertTrue(InvalidFacetManager.getInstance(myProject).invalidFacets.isEmpty())
+ val mockFacet = facetManager.getFacetsByType(MockFacetType.ID).single()
+ assertEquals("mock", mockFacet.name)
+ assertEquals("my data", mockFacet.configuration.data)
+ }
+
+ fun `test unload and load facet with sub facets`() {
+ val facetManager = FacetManager.getInstance(module)
+ runWithRegisteredFacetTypes(MockFacetType(), MockSubFacetType()) {
+ runWriteAction {
+ val model = facetManager.createModifiableModel()
+ val facet = MockFacet(module, "mock")
+ model.addFacet(facet)
+ model.addFacet(MockSubFacetType.getInstance().createFacet(module, "sub-facet", MockFacetConfiguration(), facet))
+ model.commit()
+ }
+ assertEquals("mock", facetManager.getFacetsByType(MockFacetType.ID).single().name)
+ assertEquals("sub-facet", facetManager.getFacetsByType(MockSubFacetType.ID).single().name)
+ }
+
+ assertTrue(facetManager.getFacetsByType(MockFacetType.ID).isEmpty())
+ assertTrue(facetManager.getFacetsByType(MockSubFacetType.ID).isEmpty())
+ val invalidFacet = InvalidFacetManager.getInstance(myProject).invalidFacets.single()
+ assertEquals("mock", invalidFacet.name)
+ val subFacetState = invalidFacet.configuration.facetState.subFacets.single()
+ assertEquals("sub-facet", subFacetState.name)
+
+ registerFacetType(MockFacetType(), testRootDisposable)
+ registerFacetType(MockSubFacetType(), testRootDisposable)
+
+ assertTrue(InvalidFacetManager.getInstance(myProject).invalidFacets.isEmpty())
+ val mockFacet = facetManager.getFacetsByType(MockFacetType.ID).single()
+ assertEquals("mock", mockFacet.name)
+ val mockSubFacet = facetManager.getFacetsByType(MockSubFacetType.ID).single()
+ assertEquals("sub-facet", mockSubFacet.name)
+ assertSame(mockFacet, mockSubFacet.underlyingFacet)
+ }
+
+ fun `test unload and load sub facet`() {
+ val facetManager = FacetManager.getInstance(module)
+ registerFacetType(MockFacetType(), testRootDisposable)
+ runWithRegisteredFacetTypes(MockSubFacetType()) {
+ runWriteAction {
+ val model = facetManager.createModifiableModel()
+ val facet = MockFacet(module, "mock")
+ model.addFacet(facet)
+ model.addFacet(MockSubFacetType.getInstance().createFacet(module, "sub-facet", MockFacetConfiguration(), facet))
+ model.commit()
+ }
+ assertEquals("mock", facetManager.getFacetsByType(MockFacetType.ID).single().name)
+ assertEquals("sub-facet", facetManager.getFacetsByType(MockSubFacetType.ID).single().name)
+ }
+
+ val mockFacet = facetManager.getFacetsByType(MockFacetType.ID).single()
+ assertEquals("mock", mockFacet.name)
+ assertTrue(facetManager.getFacetsByType(MockSubFacetType.ID).isEmpty())
+ val invalidFacet = InvalidFacetManager.getInstance(myProject).invalidFacets.single()
+ assertEquals("sub-facet", invalidFacet.name)
+ assertSame(mockFacet, invalidFacet.underlyingFacet)
+
+ registerFacetType(MockSubFacetType(), testRootDisposable)
+ assertTrue(InvalidFacetManager.getInstance(myProject).invalidFacets.isEmpty())
+ val mockSubFacet = facetManager.getFacetsByType(MockSubFacetType.ID).single()
+ assertEquals("sub-facet", mockSubFacet.name)
+ assertSame(mockFacet, mockSubFacet.underlyingFacet)
+ }
+
+ private inline fun runWithRegisteredFacetTypes(vararg types: FacetType<*, *>, action: () -> Unit) {
+ val disposable = Disposer.newDisposable()
+ for (type in types) {
+ registerFacetType(type, disposable)
+ }
+
+ try {
+ action()
+ }
+ finally {
+ Disposer.dispose(disposable)
+ }
+ }
+
+ private fun registerFacetType(type: FacetType<*, *>, disposable: Disposable) {
+ val facetTypeDisposable = Disposer.newDisposable()
+ Disposer.register(disposable, Disposable {
+ runWriteAction {
+ Disposer.dispose(facetTypeDisposable)
+ }
+ })
+ FacetType.EP_NAME.getPoint(null).registerExtension(type, facetTypeDisposable)
+ }
+
+ override fun setUp() {
+ super.setUp()
+ //initialize facet types and register listeners
+ FacetTypeRegistry.getInstance().facetTypes
+ }
+}
\ No newline at end of file
diff --git a/platform/lang-api/src/com/intellij/facet/FacetType.java b/platform/lang-api/src/com/intellij/facet/FacetType.java
index ed96360a5aa0..a0bea301bc79 100644
--- a/platform/lang-api/src/com/intellij/facet/FacetType.java
+++ b/platform/lang-api/src/com/intellij/facet/FacetType.java
@@ -7,6 +7,8 @@ import com.intellij.facet.ui.DefaultFacetSettingsEditor;
import com.intellij.facet.ui.FacetEditor;
import com.intellij.facet.ui.MultipleFacetSettingsEditor;
import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.PluginAware;
+import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.Project;
@@ -24,13 +26,14 @@ import javax.swing.*;
* </extensions>
*
*/
-public abstract class FacetType {
+public abstract class FacetType implements PluginAware {
public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.facetType");
private final @NotNull FacetTypeId myId;
private final @NotNull String myStringId;
private final @NotNull String myPresentableName;
private final @Nullable FacetTypeId myUnderlyingFacetType;
+ private PluginDescriptor myPluginDescriptor;
public static T findInstance(Class aClass) {
return EP_NAME.findExtension(aClass);
@@ -90,6 +93,15 @@ public abstract class FacetType {
return myUnderlyingFacetType;
}
+ @Override
+ public void setPluginDescriptor(@NotNull PluginDescriptor pluginDescriptor) {
+ myPluginDescriptor = pluginDescriptor;
+ }
+
+ public final PluginDescriptor getPluginDescriptor() {
+ return myPluginDescriptor;
+ }
+
/**
* @deprecated this method is not called by IDE core anymore. Use {@link com.intellij.framework.detection.FrameworkDetector} extension
* to provide automatic detection for facets
diff --git a/platform/lang-api/src/com/intellij/facet/ModifiableFacetModel.java b/platform/lang-api/src/com/intellij/facet/ModifiableFacetModel.java
index aabd7c4a099d..0944f436bebc 100644
--- a/platform/lang-api/src/com/intellij/facet/ModifiableFacetModel.java
+++ b/platform/lang-api/src/com/intellij/facet/ModifiableFacetModel.java
@@ -29,6 +29,13 @@ public interface ModifiableFacetModel extends FacetModel {
void addFacet(Facet> facet, @Nullable ProjectModelExternalSource externalSource);
void removeFacet(Facet> facet);
+ /**
+ * Replaces {@code original} facet by {@code replacement}. The only difference with {@code removeFacet(original); addFacet(replacement); }
+ * is that this method preserves order of facets in internal structures to avoid modifications of *.iml files.
+ */
+ @ApiStatus.Internal
+ void replaceFacet(@NotNull Facet> original, @NotNull Facet> replacement);
+
void rename(Facet> facet, String newName);
@Nullable
diff --git a/platform/lang-impl/src/com/intellij/facet/FacetManagerBase.java b/platform/lang-impl/src/com/intellij/facet/FacetManagerBase.java
index ad32997d9ea5..5b42667ce1c5 100644
--- a/platform/lang-impl/src/com/intellij/facet/FacetManagerBase.java
+++ b/platform/lang-impl/src/com/intellij/facet/FacetManagerBase.java
@@ -38,10 +38,10 @@ public abstract class FacetManagerBase extends FacetManager {
}
@NotNull
- private static , C extends FacetConfiguration> F createFacet(@NotNull Module module, @NotNull FacetType type,
- @NotNull String name,
- @NotNull C configuration,
- @Nullable Facet> underlying) {
+ protected static , C extends FacetConfiguration> F createFacet(@NotNull Module module, @NotNull FacetType type,
+ @NotNull String name,
+ @NotNull C configuration,
+ @Nullable Facet> underlying) {
final F facet = type.createFacet(module, name, configuration, underlying);
assertTrue(facet.getModule() == module, facet, "module");
assertTrue(facet.getConfiguration() == configuration, facet, "configuration");
@@ -126,17 +126,19 @@ public abstract class FacetManagerBase extends FacetManager {
@NotNull
public static InvalidFacet createInvalidFacet(@NotNull Module module, @NotNull FacetState state, @Nullable Facet> underlyingFacet,
@NotNull String errorMessage,
- boolean unknownType) {
+ boolean unknownType, boolean reportError) {
Project project = module.getProject();
- final InvalidFacetManager invalidFacetManager = InvalidFacetManager.getInstance(project);
final InvalidFacetType type = InvalidFacetType.getInstance();
final InvalidFacetConfiguration configuration = new InvalidFacetConfiguration(state, errorMessage);
final InvalidFacet facet = createFacet(module, type, StringUtil.notNullize(state.getName()), configuration, underlyingFacet);
- if (!invalidFacetManager.isIgnored(facet)) {
- FacetLoadingErrorDescription description = new FacetLoadingErrorDescription(facet);
- ProjectLoadingErrorsNotifier.getInstance(project).registerError(description);
- if (unknownType) {
- UnknownFeaturesCollector.getInstance(project).registerUnknownFeature("com.intellij.facetType", state.getFacetType(), "Facet");
+ if (reportError) {
+ InvalidFacetManager invalidFacetManager = InvalidFacetManager.getInstance(project);
+ if (!invalidFacetManager.isIgnored(facet)) {
+ FacetLoadingErrorDescription description = new FacetLoadingErrorDescription(facet);
+ ProjectLoadingErrorsNotifier.getInstance(project).registerError(description);
+ if (unknownType) {
+ UnknownFeaturesCollector.getInstance(project).registerUnknownFeature("com.intellij.facetType", state.getFacetType(), "Facet");
+ }
}
}
return facet;
diff --git a/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java b/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java
index 5d4e4d208f55..4905e204bd56 100644
--- a/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java
@@ -134,7 +134,7 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
ModifiableFacetModel model,
final Facet> underlyingFacet,
final String errorMessage, boolean unknownType) {
- model.addFacet(createInvalidFacet(getModule(), state, underlyingFacet, errorMessage, unknownType));
+ model.addFacet(createInvalidFacet(getModule(), state, underlyingFacet, errorMessage, unknownType, true));
}
private , C extends FacetConfiguration> void addFacet(final FacetType type, final FacetState state, final Facet> underlyingFacet,
@@ -161,24 +161,39 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
}
if (facet == null) {
- final C configuration = type.createDefaultConfiguration();
- final Element config = state.getConfiguration();
- FacetUtil.loadFacetConfiguration(configuration, config);
- String name = state.getName();
- facet = createFacet(type, name, configuration, underlyingFacet);
- if (facet instanceof JDOMExternalizable) {
- //todo[nik] remove
- ((JDOMExternalizable)facet).readExternal(config);
- }
- String externalSystemId = state.getExternalSystemId();
- if (externalSystemId != null) {
- facet.setExternalSource(ExternalProjectSystemRegistry.getInstance().getSourceById(externalSystemId));
- }
+ facet = createFacetFromState(getModule(), type, state, underlyingFacet);
model.addFacet(facet);
}
addFacets(state.getSubFacets(), facet, model);
}
+ @ApiStatus.Internal
+ @NotNull
+ public static Facet> createFacetFromStateRaw(@NotNull Module module, @NotNull FacetType, ?> type, @NotNull FacetState state,
+ @Nullable Facet> underlyingFacet) {
+ //noinspection unchecked
+ return createFacetFromState(module, type, state, underlyingFacet);
+ }
+
+ @NotNull
+ private static , C extends FacetConfiguration> F createFacetFromState(Module module, FacetType type,
+ FacetState state, Facet> underlyingFacet) {
+ C configuration = type.createDefaultConfiguration();
+ Element config = state.getConfiguration();
+ FacetUtil.loadFacetConfiguration(configuration, config);
+ String name = state.getName();
+ F facet = createFacet(module, type, name, configuration, underlyingFacet);
+ if (facet instanceof JDOMExternalizable) {
+ //todo[nik] remove
+ ((JDOMExternalizable)facet).readExternal(config);
+ }
+ String externalSystemId = state.getExternalSystemId();
+ if (externalSystemId != null) {
+ facet.setExternalSource(ExternalProjectSystemRegistry.getInstance().getSourceById(externalSystemId));
+ }
+ return facet;
+ }
+
@Override
public void noStateLoaded() {
doLoadState(null);
@@ -224,12 +239,8 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
if (!filter.test(facet)) continue;
final Facet> underlyingFacet = facet.getUnderlyingFacet();
- FacetState facetState = createFacetState(facet, myModule.getProject());
- if (!(facet instanceof InvalidFacet)) {
- final Element config = FacetUtil.saveFacetConfiguration(facet);
- if (config == null) continue;
- facetState.setConfiguration(config);
- }
+ FacetState facetState = saveFacetConfiguration(facet);
+ if (facetState == null) continue;
getOrCreateTargetFacetList(underlyingFacet, states, myModule.getProject()).add(facetState);
states.put(facet, facetState.getSubFacets());
@@ -237,6 +248,17 @@ public final class FacetManagerImpl extends FacetManagerBase implements ModuleCo
return managerState;
}
+ @ApiStatus.Internal
+ public static @Nullable FacetState saveFacetConfiguration(Facet> facet) {
+ FacetState facetState = createFacetState(facet, facet.getModule().getProject());
+ if (!(facet instanceof InvalidFacet)) {
+ final Element config = FacetUtil.saveFacetConfiguration(facet);
+ if (config == null) return null;
+ facetState.setConfiguration(config);
+ }
+ return facetState;
+ }
+
/**
* Configuration of some facet may be stored in one file, but configuration of its underlying facet may be stored in another file. For such
* sub-facets we create parent elements which don't store configuration but only name and type.
diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetModelImpl.java b/platform/lang-impl/src/com/intellij/facet/impl/FacetModelImpl.java
index c205fcfd2eac..373597090515 100644
--- a/platform/lang-impl/src/com/intellij/facet/impl/FacetModelImpl.java
+++ b/platform/lang-impl/src/com/intellij/facet/impl/FacetModelImpl.java
@@ -72,6 +72,15 @@ public class FacetModelImpl extends FacetModelBase implements ModifiableFacetMod
facetsChanged();
}
+ @Override
+ public void replaceFacet(@NotNull Facet> original, @NotNull Facet> replacement) {
+ int index = myFacets.indexOf(original);
+ if (index != -1) {
+ myFacets.set(index, replacement);
+ facetsChanged();
+ }
+ }
+
@Override
public void rename(final Facet> facet, final String newName) {
if (!newName.equals(facet.getName())) {
diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetTypeRegistryImpl.kt b/platform/lang-impl/src/com/intellij/facet/impl/FacetTypeRegistryImpl.kt
index 816cea5657e9..b5c75cc311aa 100644
--- a/platform/lang-impl/src/com/intellij/facet/impl/FacetTypeRegistryImpl.kt
+++ b/platform/lang-impl/src/com/intellij/facet/impl/FacetTypeRegistryImpl.kt
@@ -2,9 +2,16 @@
package com.intellij.facet.impl
import com.intellij.facet.*
+import com.intellij.facet.impl.invalid.InvalidFacetManager
+import com.intellij.facet.impl.invalid.InvalidFacetType
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.ExtensionPointListener
import com.intellij.openapi.extensions.PluginDescriptor
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ProjectManager
+import org.jetbrains.jps.model.serialization.facet.FacetState
import java.util.*
class FacetTypeRegistryImpl : FacetTypeRegistry() {
@@ -23,13 +30,72 @@ class FacetTypeRegistryImpl : FacetTypeRegistry() {
myTypeIds[id] = typeId
}
+ private fun loadInvalidFacetsOfType(project: Project, facetType: FacetType<*, *>) {
+ val modulesWithFacets = InvalidFacetManager.getInstance(project).invalidFacets
+ .filter { it.configuration.facetState.facetType == facetType.stringId }
+ .mapTo(HashSet()) { it.module }
+ for (module in modulesWithFacets) {
+ val model = FacetManager.getInstance(module).createModifiableModel()
+ val invalidFacets = model.getFacetsByType(InvalidFacetType.TYPE_ID).filter { it.configuration.facetState.facetType == facetType.stringId }
+ for (invalidFacet in invalidFacets) {
+ val newFacet = FacetManagerImpl.createFacetFromStateRaw(module, facetType, invalidFacet.configuration.facetState,
+ invalidFacet.underlyingFacet)
+ model.replaceFacet(invalidFacet, newFacet)
+ for (subFacet in invalidFacet.configuration.facetState.subFacets) {
+ model.addFacet(FacetManagerBase.createInvalidFacet(module, subFacet, newFacet, invalidFacet.configuration.errorMessage, false, false))
+ }
+ }
+ model.commit()
+ }
+ }
+
@Synchronized
override fun unregisterFacetType(facetType: FacetType<*, *>) {
- val id = facetType.id
- val stringId = facetType.stringId
- LOG.assertTrue(myFacetTypes.remove(id) != null, "Facet type '$stringId' is not registered")
- myFacetTypes.remove(id)
- myTypeIds.remove(stringId)
+ try {
+ ProjectManager.getInstance().openProjects.forEach {
+ convertFacetsToInvalid(it, facetType)
+ }
+ }
+ finally {
+ val id = facetType.id
+ val stringId = facetType.stringId
+ LOG.assertTrue(myFacetTypes.remove(id) != null, "Facet type '$stringId' is not registered")
+ myFacetTypes.remove(id)
+ myTypeIds.remove(stringId)
+ }
+ }
+
+ private fun convertFacetsToInvalid(project: Project, facetType: FacetType<*, *>) {
+ val modulesWithFacets = ProjectFacetManager.getInstance(project).getFacets(facetType.id).mapTo(HashSet()) { it.module }
+ for (module in modulesWithFacets) {
+ val model = FacetManager.getInstance(module).createModifiableModel()
+ val subFacets = model.allFacets.groupBy { it.underlyingFacet }
+ val facets = model.getFacetsByType(facetType.id)
+ for (facet in facets) {
+ val facetState = saveFacetWithSubFacets(facet, subFacets) ?: continue
+ val pluginName = facetType.pluginDescriptor?.name?.let { " '$it'" } ?: ""
+ val errorMessage = "Plugin$pluginName which provides support for '${facetType.presentableName}' facets is unloaded"
+ val reportError = !ApplicationManager.getApplication().isUnitTestMode
+ val invalidFacet = FacetManagerBase.createInvalidFacet(module, facetState, facet.underlyingFacet, errorMessage, true, reportError)
+ removeAllSubFacets(model, facet, subFacets)
+ model.replaceFacet(facet, invalidFacet)
+ }
+ model.commit()
+ }
+ }
+
+ private fun removeAllSubFacets(model: ModifiableFacetModel, facet: Facet<*>, subFacets: Map, List>>) {
+ val toRemove = subFacets[facet] ?: return
+ for (subFacet in toRemove) {
+ removeAllSubFacets(model, subFacet, subFacets)
+ model.removeFacet(subFacet)
+ }
+ }
+
+ private fun saveFacetWithSubFacets(facet: Facet<*>?, subFacets: Map, List>>): FacetState? {
+ val state = FacetManagerImpl.saveFacetConfiguration(facet) ?: return null
+ (subFacets[facet] ?: emptyList()).mapNotNullTo(state.subFacets) { saveFacetWithSubFacets(it, subFacets) }
+ return state
}
@Synchronized
@@ -72,18 +138,26 @@ class FacetTypeRegistryImpl : FacetTypeRegistry() {
if (myExtensionsLoaded) {
return
}
- FacetType.EP_NAME.getPoint(null).addExtensionPointListener(
+ FacetType.EP_NAME.forEachExtensionSafe {
+ registerFacetType(it)
+ }
+ myExtensionsLoaded = true
+ FacetType.EP_NAME.addExtensionPointListener(
object : ExtensionPointListener?> {
override fun extensionAdded(extension: FacetType<*, *>, pluginDescriptor: PluginDescriptor) {
registerFacetType(extension)
+ runWriteAction {
+ ProjectManager.getInstance().openProjects.forEach {
+ loadInvalidFacetsOfType(it, extension)
+ }
+ }
}
override fun extensionRemoved(extension: FacetType<*, *>,
pluginDescriptor: PluginDescriptor) {
unregisterFacetType(extension)
}
- }, true, null)
- myExtensionsLoaded = true
+ }, null)
}
companion object {
diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
index e1c771ddb1fa..e48d3d284298 100644
--- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
@@ -422,7 +422,7 @@
-
+
diff --git a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/FacetManagerViaWorkspaceModel.kt b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/FacetManagerViaWorkspaceModel.kt
index fdc2cdcec312..a1b7bb7f01ad 100644
--- a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/FacetManagerViaWorkspaceModel.kt
+++ b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/FacetManagerViaWorkspaceModel.kt
@@ -74,7 +74,7 @@ internal open class FacetModelViaWorkspaceModel(protected val legacyBridgeModule
name = entity.name
setFacetType(entity.facetType)
configuration = entity.configurationXmlTag?.let { JDOMUtil.load(it) }
- }, underlyingFacet, ProjectBundle.message("error.message.unknown.facet.type.0", entity.facetType), true)
+ }, underlyingFacet, ProjectBundle.message("error.message.unknown.facet.type.0", entity.facetType), true, true)
}
val configuration = facetType.createDefaultConfiguration()
diff --git a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/ModifiableFacetModelViaWorkspaceModel.kt b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/ModifiableFacetModelViaWorkspaceModel.kt
index b684f4973a34..b20b76771e7b 100644
--- a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/ModifiableFacetModelViaWorkspaceModel.kt
+++ b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/facet/ModifiableFacetModelViaWorkspaceModel.kt
@@ -47,6 +47,11 @@ internal class ModifiableFacetModelViaWorkspaceModel(private val initialStorage:
facetsChanged()
}
+ override fun replaceFacet(original: Facet<*>, replacement: Facet<*>) {
+ removeFacet(original)
+ addFacet(replacement)
+ }
+
private fun removeFacetEntityWithSubFacets(entity: FacetEntity) {
if (entity !in entityToFacet) return