mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 14:01:44 +07:00
[workspace model] store java language level in JavaModuleSettingsEntity (IDEA-266774, IDEA-270617)
This provides better API to read/change language level via workspace model storage and decreases memory usage (storing language level id instead of xml tag with attribute). In order to allow contributing implementations of ModuleExtension based on data from workspace model storage from plugins, ModuleExtensionBridgeFactory extension point is introduced. GitOrigin-RevId: 51d7e38390bb8df19e072e16a328514d6e863597
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f6b8636486
commit
c5a4251cc8
@@ -2,34 +2,14 @@
|
||||
|
||||
package com.intellij.openapi.roots;
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponentWithModificationTracker;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* This is an internal class, use {@link LanguageLevelModuleExtension} instead.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public class LanguageLevelModuleExtensionImpl extends ModuleExtension implements LanguageLevelModuleExtension,
|
||||
PersistentStateComponentWithModificationTracker<LanguageLevelState> {
|
||||
private static final Logger LOG = Logger.getInstance(LanguageLevelModuleExtensionImpl.class);
|
||||
|
||||
private Module myModule;
|
||||
private final boolean myWritable;
|
||||
|
||||
private final LanguageLevelModuleExtensionImpl mySource;
|
||||
|
||||
private LanguageLevelState myState = new LanguageLevelState();
|
||||
|
||||
@Override
|
||||
public long getStateModificationCount() {
|
||||
return myState.getModificationCount();
|
||||
}
|
||||
|
||||
public abstract class LanguageLevelModuleExtensionImpl extends ModuleExtension implements LanguageLevelModuleExtension {
|
||||
/**
|
||||
* @deprecated this method returns an implementation specific class, use {@link com.intellij.openapi.module.LanguageLevelUtil#getCustomLanguageLevel(Module)} instead.
|
||||
*/
|
||||
@@ -37,68 +17,4 @@ public class LanguageLevelModuleExtensionImpl extends ModuleExtension implements
|
||||
public static LanguageLevelModuleExtensionImpl getInstance(final Module module) {
|
||||
return ModuleRootManager.getInstance(module).getModuleExtension(LanguageLevelModuleExtensionImpl.class);
|
||||
}
|
||||
|
||||
public LanguageLevelModuleExtensionImpl(Module module) {
|
||||
myModule = module;
|
||||
mySource = null;
|
||||
myWritable = false;
|
||||
}
|
||||
|
||||
public LanguageLevelModuleExtensionImpl(final LanguageLevelModuleExtensionImpl source, boolean writable) {
|
||||
myWritable = writable;
|
||||
myModule = source.myModule;
|
||||
mySource = source;
|
||||
// setter must be used instead of creating new state with constructor param because in any case default language level for module is null (i.e. project language level)
|
||||
myState.setLanguageLevel(source.getLanguageLevel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLanguageLevel(final LanguageLevel languageLevel) {
|
||||
if (myState.getLanguageLevel() == languageLevel) return;
|
||||
|
||||
LOG.assertTrue(myWritable, "Writable model can be retrieved from writable ModifiableRootModel");
|
||||
myState.setLanguageLevel(languageLevel);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LanguageLevelState getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull LanguageLevelState state) {
|
||||
myState = state;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ModuleExtension getModifiableModel(final boolean writable) {
|
||||
return new LanguageLevelModuleExtensionImpl(this, writable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
if (isChanged()) {
|
||||
mySource.myState.setLanguageLevel(myState.getLanguageLevel());
|
||||
LanguageLevelProjectExtension.getInstance(myModule.getProject()).languageLevelsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged() {
|
||||
return mySource != null && !mySource.myState.equals(myState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
myModule = null;
|
||||
myState = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LanguageLevel getLanguageLevel() {
|
||||
return myState.getLanguageLevel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,5 +28,6 @@
|
||||
<orderEntry type="library" name="Guava" level="project" />
|
||||
<orderEntry type="library" name="fastutil-min" level="project" />
|
||||
<orderEntry type="library" name="Trove4j" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.workspaceModel.storage" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -268,6 +268,7 @@
|
||||
<syntaxHighlighter id="java.class" key="CLASS" factoryClass="com.intellij.lang.java.JavaSyntaxHighlighterFactory"/>
|
||||
<lang.syntaxHighlighterFactory language="JAVA" implementationClass="com.intellij.lang.java.JavaSyntaxHighlighterFactory"/>
|
||||
<moduleExtension implementation="com.intellij.openapi.roots.impl.JavaModuleExternalPathsImpl"/>
|
||||
<workspaceModel.moduleExtensionBridgeFactory implementation="com.intellij.workspaceModel.ide.legacyBridge.impl.java.LanguageLevelModuleExtensionBridge$Companion"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="ClassGetClass"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.probable.bugs"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// 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-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.
|
||||
package com.intellij.workspaceModel.ide.java
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.JavaModuleSettingsEntity
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModifiableJavaModuleSettingsEntity
|
||||
|
||||
var ModifiableJavaModuleSettingsEntity.languageLevel: LanguageLevel?
|
||||
get() = idToLanguageLevel(languageLevelId)
|
||||
set(value) {
|
||||
languageLevelId = value?.name
|
||||
}
|
||||
|
||||
val JavaModuleSettingsEntity.languageLevel: LanguageLevel?
|
||||
get() = idToLanguageLevel(languageLevelId)
|
||||
|
||||
private fun idToLanguageLevel(id: String?): LanguageLevel? {
|
||||
return try {
|
||||
LanguageLevel.valueOf(id ?: return null)
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// 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-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.
|
||||
package com.intellij.workspaceModel.ide.legacyBridge.impl.java
|
||||
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl
|
||||
import com.intellij.openapi.roots.ModuleExtension
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.workspaceModel.ide.java.languageLevel
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleExtensionBridge
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleExtensionBridgeFactory
|
||||
import com.intellij.workspaceModel.storage.ExternalEntityMapping
|
||||
import com.intellij.workspaceModel.storage.VersionedEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageDiffBuilder
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModifiableJavaModuleSettingsEntity
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.addJavaModuleSettingsEntity
|
||||
|
||||
class LanguageLevelModuleExtensionBridge private constructor(private val module: ModuleBridge,
|
||||
private val entityStorage: VersionedEntityStorage,
|
||||
private val diff: WorkspaceEntityStorageDiffBuilder?) : LanguageLevelModuleExtensionImpl(), ModuleExtensionBridge {
|
||||
private var changed = false
|
||||
private val moduleEntity
|
||||
get() = entityStorage.current.moduleMap.getEntities(module).firstOrNull() as ModuleEntity?
|
||||
|
||||
override fun setLanguageLevel(languageLevel: LanguageLevel?) {
|
||||
if (diff == null) error("Cannot modify data via read-only extensions")
|
||||
val moduleEntity = moduleEntity ?: error("Cannot find entity for $module")
|
||||
val javaSettings = moduleEntity.javaSettings
|
||||
if (javaSettings != null) {
|
||||
diff.modifyEntity(ModifiableJavaModuleSettingsEntity::class.java, javaSettings) {
|
||||
this.languageLevel = languageLevel
|
||||
}
|
||||
}
|
||||
else if (languageLevel != null) {
|
||||
diff.addJavaModuleSettingsEntity(inheritedCompilerOutput = true, excludeOutput = true, compilerOutput = null,
|
||||
compilerOutputForTests = null, languageLevelId = languageLevel.name, module = moduleEntity,
|
||||
source = moduleEntity.entitySource)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLanguageLevel(): LanguageLevel? {
|
||||
return moduleEntity?.javaSettings?.languageLevel
|
||||
}
|
||||
|
||||
override fun isChanged(): Boolean = changed
|
||||
|
||||
override fun getModifiableModel(writable: Boolean): ModuleExtension {
|
||||
throw UnsupportedOperationException("This method must not be called for extensions backed by workspace model")
|
||||
}
|
||||
|
||||
override fun commit() = Unit
|
||||
override fun dispose() = Unit
|
||||
|
||||
companion object : ModuleExtensionBridgeFactory<LanguageLevelModuleExtensionBridge> {
|
||||
//todo move corresponding fields from ModuleManagerComponentBridge to projectModel.impl module
|
||||
private val WorkspaceEntityStorage.moduleMap: ExternalEntityMapping<ModuleBridge>
|
||||
get() = getExternalMapping("intellij.modules.bridge")
|
||||
|
||||
override fun createExtension(module: ModuleBridge,
|
||||
entityStorage: VersionedEntityStorage,
|
||||
diff: WorkspaceEntityStorageDiffBuilder?): LanguageLevelModuleExtensionBridge {
|
||||
return LanguageLevelModuleExtensionBridge(module, entityStorage, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
<orderEntry type="module" module-name="intellij.platform.inspect" />
|
||||
<orderEntry type="library" name="fastutil-min" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.workspaceModel.storage" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.codeStyle.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.util.io" />
|
||||
|
||||
@@ -557,8 +557,6 @@
|
||||
<bundledKeymap file="NetBeans 6.5.xml"/>
|
||||
<keymapExtension implementation="com.intellij.debugger.actions.DebuggerKeymapExtension"/>
|
||||
|
||||
<moduleExtension implementation="com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl"/>
|
||||
|
||||
<orderRootType implementation="com.intellij.openapi.roots.NativeLibraryOrderRootType"/>
|
||||
|
||||
<codeUsageScopeOptimizer implementation="com.intellij.compiler.JavaCompilerReferencesCodeUsageScopeOptimizer"/>
|
||||
|
||||
@@ -10,11 +10,18 @@ import com.intellij.openapi.roots.ProjectExtension;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModelChangeListener;
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModelTopics;
|
||||
import com.intellij.workspaceModel.storage.EntityChange;
|
||||
import com.intellij.workspaceModel.storage.VersionedStorageChange;
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.JavaModuleSettingsEntity;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author anna
|
||||
*/
|
||||
@@ -29,6 +36,25 @@ public class LanguageLevelProjectExtensionImpl extends LanguageLevelProjectExten
|
||||
public LanguageLevelProjectExtensionImpl(final Project project) {
|
||||
myProject = project;
|
||||
setDefault(project.isDefault() ? true : null);
|
||||
WorkspaceModelTopics.Companion.getInstance(project).subscribeAfterModuleLoading(
|
||||
project.getMessageBus().connect(),
|
||||
new WorkspaceModelChangeListener() {
|
||||
@Override
|
||||
public void beforeChanged(@NotNull VersionedStorageChange event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(@NotNull VersionedStorageChange event) {
|
||||
if (event.getChanges(JavaModuleSettingsEntity.class).stream().anyMatch(change ->
|
||||
change instanceof EntityChange.Replaced<?> &&
|
||||
!Objects.equals(((EntityChange.Replaced<JavaModuleSettingsEntity>)change).getOldEntity().getLanguageLevelId(),
|
||||
((EntityChange.Replaced<JavaModuleSettingsEntity>)change).getNewEntity().getLanguageLevelId())
|
||||
)) {
|
||||
languageLevelsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static LanguageLevelProjectExtensionImpl getInstanceImpl(Project project) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/bar/bar.iml" filepath="$PROJECT_DIR$/bar/bar.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/foo/foo.iml" filepath="$PROJECT_DIR$/foo/foo.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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.
|
||||
package com.intellij.java.configurationStore
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.module.EffectiveLanguageLevelUtil
|
||||
import com.intellij.openapi.module.LanguageLevelUtil
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.ApplicationRule
|
||||
import com.intellij.testFramework.TemporaryDirectory
|
||||
import com.intellij.testFramework.loadProjectAndCheckResults
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
|
||||
class LoadJavaProjectTest {
|
||||
companion object {
|
||||
@JvmField
|
||||
@ClassRule
|
||||
val appRule = ApplicationRule()
|
||||
}
|
||||
|
||||
@get:Rule
|
||||
val tempDirectory = TemporaryDirectory()
|
||||
|
||||
@Test
|
||||
fun `load java project with custom language level`() {
|
||||
val projectPath = Paths.get(PathManagerEx.getCommunityHomePath()).resolve("java/java-tests/testData/configurationStore/java-module-with-custom-language-level")
|
||||
loadProjectAndCheckResults(listOf(projectPath), tempDirectory) { project ->
|
||||
val modules = ModuleManager.getInstance(project).modules.sortedBy { it.name }
|
||||
assertThat(modules).hasSize(2)
|
||||
val (bar, foo) = modules
|
||||
assertThat(foo.name).isEqualTo("foo")
|
||||
assertThat(bar.name).isEqualTo("bar")
|
||||
runReadAction {
|
||||
assertThat(EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(bar)).isEqualTo(LanguageLevel.JDK_11)
|
||||
assertThat(LanguageLevelUtil.getCustomLanguageLevel(bar)).isNull()
|
||||
assertThat(LanguageLevelModuleExtensionImpl.getInstance(bar).languageLevel).isNull()
|
||||
assertThat(EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(foo)).isEqualTo(LanguageLevel.JDK_1_8)
|
||||
assertThat(LanguageLevelUtil.getCustomLanguageLevel(foo)).isEqualTo(LanguageLevel.JDK_1_8)
|
||||
assertThat(LanguageLevelModuleExtensionImpl.getInstance(foo).languageLevel).isEqualTo(LanguageLevel.JDK_1_8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.testFramework.ParsingTestCase;
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModelTopics;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -39,6 +40,7 @@ public abstract class JavaParsingTestCase extends ParsingTestCase {
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myLanguageLevel = JavaTestUtil.getMaxRegisteredLanguageLevel();
|
||||
getProject().registerService(WorkspaceModelTopics.class, new WorkspaceModelTopics());
|
||||
getProject().registerService(LanguageLevelProjectExtension.class, new LanguageLevelProjectExtensionImpl(getProject()));
|
||||
addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory());
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ class CompilerModuleExtensionBridge(
|
||||
excludeOutput = true,
|
||||
compilerOutputForTests = null,
|
||||
compilerOutput = null,
|
||||
languageLevelId = null,
|
||||
module = moduleEntity,
|
||||
source = moduleSource
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.workspaceModel.ide.impl.legacyBridge.module.CompilerModuleEx
|
||||
import com.intellij.workspaceModel.ide.impl.legacyBridge.module.ModuleManagerComponentBridge.Companion.findModuleEntity
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModifiableRootModelBridge
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleExtensionBridge
|
||||
import com.intellij.workspaceModel.storage.CachedValue
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageBuilder
|
||||
@@ -74,7 +75,7 @@ class ModifiableRootModelBridgeImpl(
|
||||
private val virtualFileManager: VirtualFileUrlManager = VirtualFileUrlManager.getInstance(project)
|
||||
|
||||
private val extensionsDelegate = lazy {
|
||||
RootModelBridgeImpl.loadExtensions(storage = initialStorage, module = module, writable = true,
|
||||
RootModelBridgeImpl.loadExtensions(storage = entityStorageOnDiff, module = module, diff = diff, writable = true,
|
||||
parentDisposable = extensionsDisposable)
|
||||
.filterNot { compilerModuleExtensionClass.isAssignableFrom(it.javaClass) }
|
||||
}
|
||||
@@ -429,6 +430,8 @@ class ModifiableRootModelBridgeImpl(
|
||||
val element = Element("component")
|
||||
|
||||
for (extension in extensions) {
|
||||
if (extension is ModuleExtensionBridge) continue
|
||||
|
||||
extension.commit()
|
||||
|
||||
if (extension is PersistentStateComponent<*>) {
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.workspaceModel.ide.impl.legacyBridge.module.roots
|
||||
import com.intellij.configurationStore.deserializeAndLoadState
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.roots.*
|
||||
import com.intellij.openapi.roots.impl.ModuleOrderEnumerator
|
||||
import com.intellij.openapi.roots.impl.RootModelBase
|
||||
@@ -13,6 +14,8 @@ import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.workspaceModel.ide.impl.legacyBridge.module.CompilerModuleExtensionBridge
|
||||
import com.intellij.workspaceModel.ide.impl.legacyBridge.module.ModuleManagerComponentBridge.Companion.findModuleEntity
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleBridge
|
||||
import com.intellij.workspaceModel.ide.legacyBridge.ModuleExtensionBridgeFactory
|
||||
import com.intellij.workspaceModel.storage.VersionedEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageDiffBuilder
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ContentRootEntity
|
||||
@@ -32,7 +35,7 @@ internal class RootModelBridgeImpl(internal val moduleEntity: ModuleEntity?,
|
||||
private val module: ModuleBridge = rootModel.moduleBridge
|
||||
|
||||
private val extensions by lazy {
|
||||
loadExtensions(storage = storage, module = module, writable = false, parentDisposable = this)
|
||||
loadExtensions(storage = VersionedEntityStorageOnStorage(storage), module = module, writable = false, diff = null, parentDisposable = this)
|
||||
}
|
||||
|
||||
private val orderEntriesArray: Array<OrderEntry> by lazy {
|
||||
@@ -99,6 +102,8 @@ internal class RootModelBridgeImpl(internal val moduleEntity: ModuleEntity?,
|
||||
override fun orderEntries(): OrderEnumerator = ModuleOrderEnumerator(this, null)
|
||||
|
||||
companion object {
|
||||
private val MODULE_EXTENSION_BRIDGE_FACTORY_EP = ExtensionPointName<ModuleExtensionBridgeFactory<*>>("com.intellij.workspaceModel.moduleExtensionBridgeFactory")
|
||||
|
||||
internal fun toOrderEntry(
|
||||
item: ModuleDependencyItem,
|
||||
index: Int,
|
||||
@@ -116,16 +121,21 @@ internal class RootModelBridgeImpl(internal val moduleEntity: ModuleEntity?,
|
||||
}
|
||||
}
|
||||
|
||||
internal fun loadExtensions(storage: WorkspaceEntityStorage,
|
||||
internal fun loadExtensions(storage: VersionedEntityStorage,
|
||||
module: ModuleBridge,
|
||||
writable: Boolean,
|
||||
diff: WorkspaceEntityStorageDiffBuilder?,
|
||||
parentDisposable: Disposable): Set<ModuleExtension> {
|
||||
|
||||
val result = TreeSet<ModuleExtension> { o1, o2 ->
|
||||
Comparing.compare(o1.javaClass.name, o2.javaClass.name)
|
||||
}
|
||||
|
||||
val moduleEntity = storage.findModuleEntity(module)
|
||||
MODULE_EXTENSION_BRIDGE_FACTORY_EP.extensionList.mapTo(result) {
|
||||
it.createExtension(module, storage, diff)
|
||||
}
|
||||
|
||||
val moduleEntity = storage.current.findModuleEntity(module)
|
||||
val rootManagerElement = moduleEntity?.customImlData?.rootManagerTagCustomData?.let { JDOMUtil.load(it) }
|
||||
|
||||
for (extension in ModuleRootManagerEx.MODULE_EXTENSION_NAME.getExtensions(module)) {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
<extensionPoint name="directoryIndexExcludePolicy" interface="com.intellij.openapi.roots.impl.DirectoryIndexExcludePolicy"
|
||||
area="IDEA_PROJECT" dynamic="true"/>
|
||||
<extensionPoint name="projectExtension" interface="com.intellij.openapi.roots.ProjectExtension" area="IDEA_PROJECT" dynamic="true"/>
|
||||
<extensionPoint name="workspaceModel.moduleExtensionBridgeFactory"
|
||||
interface="com.intellij.workspaceModel.ide.legacyBridge.ModuleExtensionBridgeFactory"
|
||||
dynamic="true"/>
|
||||
</extensionPoints>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<projectService serviceInterface="com.intellij.openapi.roots.impl.DirectoryIndex"
|
||||
|
||||
@@ -0,0 +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.
|
||||
package com.intellij.workspaceModel.ide.legacyBridge
|
||||
|
||||
/**
|
||||
* Marker interface for implementations of [com.intellij.openapi.roots.ModuleExtension] which are created via [ModuleExtensionBridgeFactory].
|
||||
*/
|
||||
interface ModuleExtensionBridge {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
package com.intellij.workspaceModel.ide.legacyBridge
|
||||
|
||||
import com.intellij.openapi.roots.ModuleExtension
|
||||
import com.intellij.workspaceModel.storage.VersionedEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageDiffBuilder
|
||||
|
||||
/**
|
||||
* Register implementation of this interface as `com.intellij.workspaceModel.moduleExtensionBridgeFactory` extension to provide implementations
|
||||
* of [ModuleExtension] based on data from workspace model.
|
||||
*/
|
||||
interface ModuleExtensionBridgeFactory<T> where T : ModuleExtension, T : ModuleExtensionBridge {
|
||||
fun createExtension(module: ModuleBridge, entityStorage: VersionedEntityStorage, diff: WorkspaceEntityStorageDiffBuilder?): T
|
||||
}
|
||||
@@ -307,6 +307,7 @@ internal open class ModuleImlFileEntitiesSerializer(internal val modulePath: Mod
|
||||
}
|
||||
|
||||
val inheritedCompilerOutput = rootManagerElement.getAttributeAndDetach(INHERIT_COMPILER_OUTPUT_ATTRIBUTE)
|
||||
val languageLevel = rootManagerElement.getAttributeAndDetach(MODULE_LANGUAGE_LEVEL_ATTRIBUTE)
|
||||
val excludeOutput = rootManagerElement.getChildAndDetach(EXCLUDE_OUTPUT_TAG) != null
|
||||
val compilerOutput = rootManagerElement.getChildAndDetach(OUTPUT_TAG)?.getAttributeValue(URL_ATTRIBUTE)
|
||||
val compilerOutputForTests = rootManagerElement.getChildAndDetach(TEST_OUTPUT_TAG)?.getAttributeValue(URL_ATTRIBUTE)
|
||||
@@ -316,6 +317,7 @@ internal open class ModuleImlFileEntitiesSerializer(internal val modulePath: Mod
|
||||
excludeOutput = excludeOutput,
|
||||
compilerOutput = compilerOutput?.let { virtualFileManager.fromUrl(it) },
|
||||
compilerOutputForTests = compilerOutputForTests?.let { virtualFileManager.fromUrl(it) },
|
||||
languageLevelId = languageLevel,
|
||||
module = moduleEntity,
|
||||
source = entitySource
|
||||
)
|
||||
@@ -490,6 +492,9 @@ internal open class ModuleImlFileEntitiesSerializer(internal val modulePath: Mod
|
||||
if (javaSettings.excludeOutput) {
|
||||
rootManagerElement.addContent(Element(EXCLUDE_OUTPUT_TAG))
|
||||
}
|
||||
javaSettings.languageLevelId?.let {
|
||||
rootManagerElement.setAttribute(MODULE_LANGUAGE_LEVEL_ATTRIBUTE, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveDependencyItem(dependencyItem: ModuleDependencyItem, moduleLibraries: Map<String, LibraryEntity>)
|
||||
|
||||
@@ -46,7 +46,7 @@ class ImlSerializationTest {
|
||||
checkSerializationSize(bytes, expectedSize, 2_000)
|
||||
|
||||
assertTrue("This assertion is a reminder. Have you updated the serializer? Update the serializer version!",
|
||||
26_000 == expectedSize && "v19" == EntityStorageSerializerImpl.SERIALIZER_VERSION)
|
||||
26_000 == expectedSize && "v20" == EntityStorageSerializerImpl.SERIALIZER_VERSION)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -98,7 +98,7 @@ class JpsProjectEntitiesLoaderTest : HeavyPlatformTestCase() {
|
||||
|
||||
val utilModule = modules[1]
|
||||
assertEquals("util", utilModule.name)
|
||||
assertEquals("""<component LANGUAGE_LEVEL="JDK_1_7">
|
||||
assertEquals("""<component>
|
||||
<annotation-paths>
|
||||
<root url="$projectUrl/lib/anno" />
|
||||
</annotation-paths>
|
||||
@@ -109,6 +109,7 @@ class JpsProjectEntitiesLoaderTest : HeavyPlatformTestCase() {
|
||||
val utilJavaSettings = utilModule.javaSettings!!
|
||||
assertEquals(false, utilJavaSettings.inheritedCompilerOutput)
|
||||
assertEquals(true, utilJavaSettings.excludeOutput)
|
||||
assertEquals("JDK_1_7", utilJavaSettings.languageLevelId)
|
||||
assertEquals("$projectUrl/out/production-util", utilJavaSettings.compilerOutput?.url)
|
||||
assertEquals("$projectUrl/out/test-util", utilJavaSettings.compilerOutputForTests?.url)
|
||||
val utilContentRoot = assertOneElement(utilModule.contentRoots.toList())
|
||||
|
||||
@@ -4,10 +4,10 @@ import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testFramework.HeavyPlatformTestCase
|
||||
import com.intellij.workspaceModel.ide.getInstance
|
||||
import com.intellij.workspaceModel.storage.url.VirtualFileUrlManager
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageBuilder
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.projectLibraries
|
||||
import com.intellij.workspaceModel.storage.url.VirtualFileUrlManager
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.io.File
|
||||
|
||||
@@ -27,7 +27,7 @@ class JpsProjectReloadingTest : HeavyPlatformTestCase() {
|
||||
assertEquals("util", utilModule.name)
|
||||
val utilModuleSrc = assertOneElement(utilModule.sourceRoots.toList())
|
||||
assertEquals("$projectDirUrl/util/src2", utilModuleSrc.url.url)
|
||||
assertEquals("""<component LANGUAGE_LEVEL="JDK_1_7">
|
||||
assertEquals("""<component>
|
||||
<annotation-paths>
|
||||
<root url="$projectDirUrl/lib/anno2" />
|
||||
</annotation-paths>
|
||||
|
||||
@@ -39,7 +39,7 @@ class JpsProjectSaveAfterChangesTest {
|
||||
url = configLocation.baseDirectoryUrl.append("util/src2")
|
||||
}
|
||||
builder.modifyEntity(ModifiableModuleCustomImlDataEntity::class.java, utilModule.customImlData!!) {
|
||||
rootManagerTagCustomData = """<component LANGUAGE_LEVEL="JDK_1_7">
|
||||
rootManagerTagCustomData = """<component>
|
||||
<annotation-paths>
|
||||
<root url="${configLocation.baseDirectoryUrlString}/lib/anno2" />
|
||||
</annotation-paths>
|
||||
@@ -96,7 +96,7 @@ class JpsProjectSaveAfterChangesTest {
|
||||
val sourceRootEntity = builder.addSourceRootEntity(contentRootEntity, configLocation.baseDirectoryUrl.append("new"),
|
||||
false, "java-source", source)
|
||||
builder.addJavaSourceRootEntity(sourceRootEntity, false, "")
|
||||
builder.addJavaModuleSettingsEntity(true, true, null, null, module, source)
|
||||
builder.addJavaModuleSettingsEntity(true, true, null, null, null, module, source)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,9 +147,10 @@ class JavaModuleSettingsEntityData : WorkspaceEntityData<JavaModuleSettingsEntit
|
||||
var excludeOutput: Boolean = false
|
||||
var compilerOutput: VirtualFileUrl? = null
|
||||
var compilerOutputForTests: VirtualFileUrl? = null
|
||||
var languageLevelId: String? = null
|
||||
|
||||
override fun createEntity(snapshot: WorkspaceEntityStorage): JavaModuleSettingsEntity {
|
||||
return JavaModuleSettingsEntity(inheritedCompilerOutput, excludeOutput, compilerOutput, compilerOutputForTests)
|
||||
return JavaModuleSettingsEntity(inheritedCompilerOutput, excludeOutput, compilerOutput, compilerOutputForTests, languageLevelId)
|
||||
.also { addMetaData(it, snapshot) }
|
||||
}
|
||||
}
|
||||
@@ -158,7 +159,8 @@ class JavaModuleSettingsEntity(
|
||||
val inheritedCompilerOutput: Boolean,
|
||||
val excludeOutput: Boolean,
|
||||
val compilerOutput: VirtualFileUrl?,
|
||||
val compilerOutputForTests: VirtualFileUrl?
|
||||
val compilerOutputForTests: VirtualFileUrl?,
|
||||
val languageLevelId: String?
|
||||
) : WorkspaceEntityBase() {
|
||||
val module: ModuleEntity by moduleDelegate
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ class ModifiableJavaModuleSettingsEntity : ModifiableWorkspaceEntityBase<JavaMod
|
||||
var excludeOutput: Boolean by EntityDataDelegation()
|
||||
var compilerOutput: VirtualFileUrl? by VirtualFileUrlNullableProperty()
|
||||
var compilerOutputForTests: VirtualFileUrl? by VirtualFileUrlNullableProperty()
|
||||
var languageLevelId: String? by EntityDataDelegation()
|
||||
|
||||
var module: ModuleEntity by MutableOneToOneChild.NotNull(JavaModuleSettingsEntity::class.java, ModuleEntity::class.java, true)
|
||||
}
|
||||
@@ -48,6 +49,7 @@ fun WorkspaceEntityStorageDiffBuilder.addJavaModuleSettingsEntity(inheritedCompi
|
||||
excludeOutput: Boolean,
|
||||
compilerOutput: VirtualFileUrl?,
|
||||
compilerOutputForTests: VirtualFileUrl?,
|
||||
languageLevelId: String?,
|
||||
module: ModuleEntity,
|
||||
source: EntitySource) = addEntity(
|
||||
ModifiableJavaModuleSettingsEntity::class.java, source) {
|
||||
@@ -55,6 +57,7 @@ fun WorkspaceEntityStorageDiffBuilder.addJavaModuleSettingsEntity(inheritedCompi
|
||||
this.excludeOutput = excludeOutput
|
||||
this.compilerOutput = compilerOutput
|
||||
this.compilerOutputForTests = compilerOutputForTests
|
||||
this.languageLevelId = languageLevelId
|
||||
this.module = module
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class EntityStorageSerializerImpl(
|
||||
private val versionsContributor: () -> Map<String, String> = { emptyMap() },
|
||||
) : EntityStorageSerializer {
|
||||
companion object {
|
||||
const val SERIALIZER_VERSION = "v19"
|
||||
const val SERIALIZER_VERSION = "v20"
|
||||
}
|
||||
|
||||
private val KRYO_BUFFER_SIZE = 64 * 1024
|
||||
|
||||
@@ -84,7 +84,7 @@ class EclipseModuleRootsSerializer : CustomModuleRootsSerializer, StorageManager
|
||||
virtualFileManager)
|
||||
}
|
||||
else {
|
||||
builder.addJavaModuleSettingsEntity(false, true, storageRootUrl.append("bin"), null, moduleEntity, entitySource)
|
||||
builder.addJavaModuleSettingsEntity(false, true, storageRootUrl.append("bin"), null, null, moduleEntity, entitySource)
|
||||
}
|
||||
|
||||
val emlUrl = getEmlFileUrl(imlFileUrl)
|
||||
@@ -101,7 +101,7 @@ class EclipseModuleRootsSerializer : CustomModuleRootsSerializer, StorageManager
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.addJavaModuleSettingsEntity(true, false, null, null, moduleEntity, entitySource)
|
||||
builder.addJavaModuleSettingsEntity(true, false, null, null, null, moduleEntity, entitySource)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,7 +199,7 @@ class EclipseModuleRootsSerializer : CustomModuleRootsSerializer, StorageManager
|
||||
outputUrl = getUrlByRelativePath(path)
|
||||
}
|
||||
builder.addJavaModuleSettingsEntity(false, true, outputUrl, null,
|
||||
moduleEntity, contentRootEntity.entitySource)
|
||||
null, moduleEntity, contentRootEntity.entitySource)
|
||||
}
|
||||
EclipseXml.LIB_KIND -> {
|
||||
val linked = expandLinkedResourcesPath(storageRootPath, expandMacroMap, path)
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.jetbrains.idea.eclipse.config
|
||||
|
||||
import com.intellij.openapi.components.ExpandMacroToPathMap
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.workspaceModel.ide.toPath
|
||||
@@ -28,8 +27,7 @@ internal class EmlFileLoader(
|
||||
private val virtualFileManager: VirtualFileUrlManager
|
||||
) {
|
||||
fun loadEml(emlTag: Element, contentRoot: ContentRootEntity) {
|
||||
loadLanguageLevel(emlTag)
|
||||
loadCompilerSettings(emlTag)
|
||||
loadCustomJavaSettings(emlTag)
|
||||
loadContentEntries(emlTag, contentRoot)
|
||||
loadJdkSettings(emlTag)
|
||||
|
||||
@@ -143,8 +141,8 @@ internal class EmlFileLoader(
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCompilerSettings(emlTag: Element) {
|
||||
val javaSettings = module.javaSettings ?: builder.addJavaModuleSettingsEntity(true, true, null, null, module, module.entitySource)
|
||||
private fun loadCustomJavaSettings(emlTag: Element) {
|
||||
val javaSettings = module.javaSettings ?: builder.addJavaModuleSettingsEntity(true, true, null, null, null, module, module.entitySource)
|
||||
builder.modifyEntity(ModifiableJavaModuleSettingsEntity::class.java, javaSettings) {
|
||||
val testOutputElement = emlTag.getChild(IdeaXml.OUTPUT_TEST_TAG)
|
||||
if (testOutputElement != null) {
|
||||
@@ -157,22 +155,8 @@ internal class EmlFileLoader(
|
||||
}
|
||||
|
||||
excludeOutput = emlTag.getChild(IdeaXml.EXCLUDE_OUTPUT_TAG) != null
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadLanguageLevel(emlTag: Element) {
|
||||
val languageLevelAttribute = emlTag.getAttributeValue("LANGUAGE_LEVEL")
|
||||
if (languageLevelAttribute != null) {
|
||||
val languageLevelTag = JDOMUtil.write(Element("component").setAttribute("LANGUAGE_LEVEL", languageLevelAttribute))
|
||||
val customImlData = module.customImlData
|
||||
if (customImlData != null) {
|
||||
builder.modifyEntity(ModifiableModuleCustomImlDataEntity::class.java, customImlData) {
|
||||
rootManagerTagCustomData = languageLevelTag
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.addModuleCustomImlDataEntity(languageLevelTag, emptyMap(), module, module.entitySource)
|
||||
}
|
||||
languageLevelId = emlTag.getAttributeValue("LANGUAGE_LEVEL")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,11 +157,7 @@ internal class EmlFileSaver(private val module: ModuleEntity,
|
||||
if (javaSettings.excludeOutput) {
|
||||
root.addContent(Element(EXCLUDE_OUTPUT_TAG))
|
||||
}
|
||||
}
|
||||
|
||||
module.customImlData?.rootManagerTagCustomData?.let { languageLevelTagString ->
|
||||
val tag = JDOMUtil.load(languageLevelTagString)
|
||||
tag.getAttributeValue("LANGUAGE_LEVEL")?.let {
|
||||
javaSettings.languageLevelId?.let {
|
||||
root.setAttribute("LANGUAGE_LEVEL", it)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user