IDEA-240086 fixed merging of local and external compiler settings

GitOrigin-RevId: 394ce505b523979f7b686edb95a132979c6f57c4
This commit is contained in:
Sergei Vorobyov
2020-06-06 19:26:38 +03:00
committed by intellij-monorepo-bot
parent 4697f052ba
commit bd0c3a800e
6 changed files with 105 additions and 7 deletions
@@ -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<String, String> externalState = ExternalCompilerConfigurationStorage.getInstance(myProject).getLoadedState();
loadStateFromExternalStorage();
}
private void loadStateFromExternalStorage() {
ExternalCompilerConfigurationStorage externalStorage = ExternalCompilerConfigurationStorage.getInstance(myProject);
Map<String, String> externalState = externalStorage.getLoadedState();
if (externalState != null) {
myModuleBytecodeTarget.putAll(externalState);
}
@@ -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;
}
@@ -83,6 +83,39 @@ internal class JDOMUtilTest {
</component>""")
}
@Test
fun `test reduce children`() {
val element = JDOMUtil.load("""
| <component name="CompilerConfiguration">
| <bytecodeTargetLevel target="1.7">
| <module name="module1" target="11" />
| </bytecodeTargetLevel>
| <bytecodeTargetLevel>
| <module name="module2" target="13" />
| <module name="module3" target="14" />
| </bytecodeTargetLevel>
| </component>""".trimMargin()
)
assertThat(JDOMUtil.reduceChildren("bytecodeTargetLevel", element))
.isEqualTo("""
| <bytecodeTargetLevel target="1.7">
| <module name="module1" target="11" />
| <module name="module2" target="13" />
| <module name="module3" target="14" />
| </bytecodeTargetLevel>""".trimMargin()
)
assertThat(element)
.isEqualTo("""
| <component name="CompilerConfiguration">
| <bytecodeTargetLevel target="1.7">
| <module name="module1" target="11" />
| <module name="module2" target="13" />
| <module name="module3" target="14" />
| </bytecodeTargetLevel>
| </component>""".trimMargin()
)
}
@Test
fun testBillionLaughs() {
assertThatThrownBy {
@@ -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<Element> children = parent.getChildren(name);
Iterator<Element> 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 <pre>{@code
@@ -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<GroovyBuilder>)it -> it
.property("sourceCompatibility", 7)
.property("targetCompatibility", 7))
.withTaskConfiguration("compileJava", (Consumer<GroovyBuilder>)it -> it
.property("sourceCompatibility", 8)
.property("targetCompatibility", 8))
.generate()
);
compileModules("project.main");
}
@Override
protected boolean useDirectoryBasedStorageFormat() {
return true;
@@ -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<GroovyBuilder>) =
withPrefix(configure::consume)
fun withTaskConfiguration(name: String, configure: Consumer<GroovyBuilder>) =
withTaskConfiguration(name, configure::consume)
fun withPrefix(configure: GroovyBuilder.() -> Unit) = apply {
addPrefix(GroovyBuilder.generate(configure = configure))
}