From bd0c3a800eea900d64f4b907ec2cf5eb27a0d200 Mon Sep 17 00:00:00 2001 From: Sergei Vorobyov Date: Thu, 4 Jun 2020 20:23:45 +0300 Subject: [PATCH] IDEA-240086 fixed merging of local and external compiler settings GitOrigin-RevId: 394ce505b523979f7b686edb95a132979c6f57c4 --- .../compiler/CompilerConfigurationImpl.java | 12 ++++++- .../model/serialization/JpsProjectLoader.java | 16 +++++---- .../testSrc/com/intellij/util/JDOMUtilTest.kt | 33 +++++++++++++++++++ .../com/intellij/openapi/util/JDOMUtil.java | 13 ++++++++ .../GradleJpsJavaCompilationTest.java | 31 +++++++++++++++++ .../importing/GradleBuildScriptBuilderEx.kt | 7 ++++ 6 files changed, 105 insertions(+), 7 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index a2587505f698..97e2e4d2851b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -726,6 +726,11 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements return true; } + @Override + public void noStateLoaded() { + loadStateFromExternalStorage(); + } + @Override public void loadState(@NotNull Element parentNode) { myState = XmlSerializer.deserialize(parentNode, State.class); @@ -816,7 +821,12 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements readByteTargetLevel(parentNode, myModuleBytecodeTarget); } - Map externalState = ExternalCompilerConfigurationStorage.getInstance(myProject).getLoadedState(); + loadStateFromExternalStorage(); + } + + private void loadStateFromExternalStorage() { + ExternalCompilerConfigurationStorage externalStorage = ExternalCompilerConfigurationStorage.getInstance(myProject); + Map externalState = externalStorage.getLoadedState(); if (externalState != null) { myModuleBytecodeTarget.putAll(externalState); } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java index 067ff55008ff..e93382e2cc09 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java @@ -45,6 +45,8 @@ import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import static org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerConfigurationSerializer.BYTECODE_TARGET_LEVEL; + public final class JpsProjectLoader extends JpsLoaderBase { public static final String MODULE_MANAGER_COMPONENT = "ProjectModuleManager"; public static final String MODULES_TAG = "modules"; @@ -128,12 +130,14 @@ public final class JpsProjectLoader extends JpsLoaderBase { break; } } - if (data == null) { - return externalData; - } - else if (externalData != null) { - return JDOMUtil.deepMerge(data, externalData); - } + return deepMergeCompilerConfigurations(data, externalData); + } + + private static @Nullable Element deepMergeCompilerConfigurations(@Nullable Element data, @Nullable Element externalData) { + if (data == null) return externalData; + if (externalData == null) return data; + JDOMUtil.deepMerge(data, externalData); + JDOMUtil.reduceChildren(BYTECODE_TARGET_LEVEL, data); return data; } diff --git a/platform/platform-tests/testSrc/com/intellij/util/JDOMUtilTest.kt b/platform/platform-tests/testSrc/com/intellij/util/JDOMUtilTest.kt index 4b514cc75510..17ee9d3938f7 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/JDOMUtilTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/util/JDOMUtilTest.kt @@ -83,6 +83,39 @@ internal class JDOMUtilTest { """) } + @Test + fun `test reduce children`() { + val element = JDOMUtil.load(""" + | + | + | + | + | + | + | + | + | """.trimMargin() + ) + assertThat(JDOMUtil.reduceChildren("bytecodeTargetLevel", element)) + .isEqualTo(""" + | + | + | + | + | """.trimMargin() + ) + assertThat(element) + .isEqualTo(""" + | + | + | + | + | + | + | """.trimMargin() + ) + } + @Test fun testBillionLaughs() { assertThatThrownBy { diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java index 3b52ccb4277d..ca09954c8d45 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java @@ -760,6 +760,7 @@ public final class JDOMUtil { return e.hasAttributes() ? e.getAttributes() : Collections.emptyList(); } + @Contract("_, !null -> !null; !null, _ -> !null") public static @Nullable Element merge(@Nullable Element to, @Nullable Element from) { if (from == null) { return to; @@ -811,6 +812,18 @@ public final class JDOMUtil { return to; } + public static @Nullable Element reduceChildren(@NotNull String name, @NotNull Element parent) { + List children = parent.getChildren(name); + Iterator it = children.iterator(); + if (!it.hasNext()) return null; + Element accumulator = it.next(); + while (it.hasNext()) { + merge(accumulator, it.next()); + it.remove(); + } + return accumulator; + } + /** * Interns {@code element} to reduce instance count of many identical Elements created after loading JDOM document to memory. * For example, after interning
{@code
diff --git a/plugins/gradle/java/testSources/compiler/GradleJpsJavaCompilationTest.java b/plugins/gradle/java/testSources/compiler/GradleJpsJavaCompilationTest.java
index 2d97a989b85b..fdd8792d804e 100644
--- a/plugins/gradle/java/testSources/compiler/GradleJpsJavaCompilationTest.java
+++ b/plugins/gradle/java/testSources/compiler/GradleJpsJavaCompilationTest.java
@@ -2,6 +2,9 @@
 package org.jetbrains.plugins.gradle.compiler;
 
 import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
+import com.intellij.util.Consumer;
+import org.jetbrains.plugins.gradle.importing.GradleBuildScriptBuilderEx;
+import org.jetbrains.plugins.gradle.importing.GroovyBuilder;
 import org.junit.Test;
 
 import java.io.IOException;
@@ -21,6 +24,34 @@ public class GradleJpsJavaCompilationTest extends GradleJpsCompilingTestCase {
     compileModules("project.main", "project.test", "project.intTest");
   }
 
+  @Test
+  public void testDifferentTargetCompatibilityForProjectAndModules() throws IOException {
+    ExternalProjectsManagerImpl.getInstance(myProject).setStoreExternally(true);
+    createProjectSubFile(
+      "src/main/java/Main.java",
+      "public class Main {\n" +
+      "    public static void main(String[] args) {\n" +
+      "        run(() -> System.out.println(\"Hello Home!\"));\n" +
+      "    }\n" +
+      "\n" +
+      "    public static void run(Runnable runnable) {\n" +
+      "        runnable.run();\n" +
+      "    }\n" +
+      "}\n");
+    importProject(
+      new GradleBuildScriptBuilderEx()
+        .withJavaPlugin()
+        .withPrefix((Consumer)it -> it
+          .property("sourceCompatibility", 7)
+          .property("targetCompatibility", 7))
+        .withTaskConfiguration("compileJava", (Consumer)it -> it
+          .property("sourceCompatibility", 8)
+          .property("targetCompatibility", 8))
+        .generate()
+    );
+    compileModules("project.main");
+  }
+
   @Override
   protected boolean useDirectoryBasedStorageFormat() {
     return true;
diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleBuildScriptBuilderEx.kt b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleBuildScriptBuilderEx.kt
index 8d032d9d1dba..7990d67194c0 100644
--- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleBuildScriptBuilderEx.kt
+++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleBuildScriptBuilderEx.kt
@@ -2,6 +2,7 @@
 package org.jetbrains.plugins.gradle.importing
 
 import com.intellij.openapi.util.io.FileUtil
+import com.intellij.util.Consumer
 import java.io.File
 
 class GradleBuildScriptBuilderEx : GradleBuildScriptBuilder() {
@@ -42,6 +43,12 @@ class GradleBuildScriptBuilderEx : GradleBuildScriptBuilder() {
     """.trimIndent())
   }
 
+  fun withPrefix(configure: Consumer) =
+    withPrefix(configure::consume)
+
+  fun withTaskConfiguration(name: String, configure: Consumer) =
+    withTaskConfiguration(name, configure::consume)
+
   fun withPrefix(configure: GroovyBuilder.() -> Unit) = apply {
     addPrefix(GroovyBuilder.generate(configure = configure))
   }