diff --git a/.idea/libraries/netty_jps.xml b/.idea/libraries/netty_jps.xml new file mode 100644 index 000000000000..379ad7490cc0 --- /dev/null +++ b/.idea/libraries/netty_jps.xml @@ -0,0 +1,81 @@ + + + + + + c1c3092e02e8037c18d14034919af68d573a71e7118db48129e6f299b9a71adc + + + 4a7b331d3770c566ab70eb02a0d1feed63b95cf6e4d68c8fe778c4c9de2d116d + + + cd189afb70ec6eacfcdfdd3a5f472b4e705a5c91d5bd3ef0386421f2ae15ec77 + + + e6dbe971c59373bbae9802021c63b9bc1d8800fead382863d67e79e79b023166 + + + cbed9829a5d582e91e314e209edce9a0c2eb369f23bb4fb74a5bc8b7990222c2 + + + 39f1b5a2aaa4eab5d036dfd0486e35a4276df412e092d36b2d88b494705a134d + + + 5972028cc863b74927ce0d11fb8d58f65da2560bef5602fe8ce8903bd306ca07 + + + 7b3455d14f59828765a00573bc3967dc59379e874bd62a67eb1926d6512109d1 + + + c3d71faaa736ffd2c9260ab0b498024b814c39c7d764bea8113fa98de6e2bdd2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/src/org/jetbrains/intellij/build/CommunityStandaloneJpsBuilder.kt b/build/src/org/jetbrains/intellij/build/CommunityStandaloneJpsBuilder.kt index 58702006a704..d75140291fb0 100644 --- a/build/src/org/jetbrains/intellij/build/CommunityStandaloneJpsBuilder.kt +++ b/build/src/org/jetbrains/intellij/build/CommunityStandaloneJpsBuilder.kt @@ -84,8 +84,7 @@ suspend fun buildCommunityStandaloneJpsBuilder(targetDir: Path, "Log4J", "jgoodies-forms", "Eclipse", - "netty-codec-http", - "netty-codec-protobuf", + "netty-jps", "lz4-java", "commons-codec", "commons-logging", @@ -99,7 +98,6 @@ suspend fun buildCommunityStandaloneJpsBuilder(targetDir: Path, "kotlin-stdlib", "commons-lang3", "maven-resolver-provider", - "netty-buffer", "aalto-xml", "caffeine", "mvstore", diff --git a/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java b/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java index 901a105d02f2..4a8762cdc081 100644 --- a/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java +++ b/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java @@ -1,3 +1,4 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler; import com.intellij.openapi.module.Module; @@ -10,6 +11,8 @@ import com.intellij.util.io.Compressor; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.impl.java.JavacCompilerTool; +import org.jetbrains.jps.builders.java.CannotCreateJavaCompilerException; import org.jetbrains.jps.javac.JpsJavacFileManager; import org.jetbrains.jps.javac.OutputFileObject; import org.jetbrains.jps.javac.ZipFileObject; @@ -57,7 +60,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { } final VirtualFile srcFile = createFile("src/A.java", "import ppp.B; public class A { B b; }"); - final StandardJavaFileManager stdFileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { + final StandardJavaFileManager stdFileManager = getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { @Override public void report(Diagnostic diagnostic) { } @@ -91,7 +94,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { final VirtualFile clsFile = createFile("out/ppp/B.class", "package ppp; public class B {}"); final File outputRoot = new File(javaFile.getParent().getParent().getPath()); - final StandardJavaFileManager stdFileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { + final StandardJavaFileManager stdFileManager = getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { @Override public void report(Diagnostic diagnostic) { } @@ -126,7 +129,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { jar.addFile("arch/B.java", new File(srcBFile.getPath())); } - final StandardJavaFileManager stdFileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { + final StandardJavaFileManager stdFileManager = getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { @Override public void report(Diagnostic diagnostic) { } @@ -179,7 +182,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { final VirtualFile srcBFile = createFile("src/B.java", "public class B {}"); final File srcRoot = new File(srcAFile.getParent().getPath()); - final StandardJavaFileManager stdFileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { + final StandardJavaFileManager stdFileManager = getSystemJavaCompiler().getStandardFileManager(new DiagnosticListener<>() { @Override public void report(Diagnostic diagnostic) { } @@ -211,6 +214,15 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { } } + private static JavaCompiler getSystemJavaCompiler() throws IOException{ + try { + return new JavacCompilerTool().createCompiler(); + } + catch (CannotCreateJavaCompilerException e) { + throw new IOException(e); + } + } + private static void checkFileObjectsBelongToLocation(JpsJavacFileManager fileManager, final JavaFileManager.Location location, Iterable fileObjects) throws IOException { for (FileObject source : fileObjects) { assertTrue(source.getName() + " should belong to " + location.getName(), fileManager.contains(location, source)); diff --git a/java/plugin/plugin-content.yaml b/java/plugin/plugin-content.yaml index b70fad3ca564..03f9358ef297 100644 --- a/java/plugin/plugin-content.yaml +++ b/java/plugin/plugin-content.yaml @@ -18,6 +18,11 @@ - name: intellij.java.frontback.psi.impl - name: intellij.java.debugger.impl.shared - name: lib/java-impl.jar + projectLibraries: + - name: netty-codec-protobuf + files: + - name: $MAVEN_REPOSITORY$/io/netty/netty-codec-protobuf/4/netty-codec-protobuf-4.jar + reason: <- intellij.java.compiler.impl modules: - name: intellij.java.compiler - name: intellij.java.debugger @@ -136,11 +141,19 @@ - name: lib/modules/intellij.jvm.analysis.impl.jar contentModules: - name: intellij.jvm.analysis.impl -- name: lib/netty-codec-protobuf.jar - projectLibraries: - - name: netty-codec-protobuf - files: - - name: $MAVEN_REPOSITORY$/io/netty/netty-codec-protobuf/4/netty-codec-protobuf-4.jar - reason: withProjectLibrary - name: lib/rt/debugger-agent.jar +- name: lib/rt/netty-jps.jar + projectLibraries: + - name: netty-jps + files: + - name: $MAVEN_REPOSITORY$/io/netty/netty-all/4/netty-all-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-buffer/4/netty-buffer-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-codec/4/netty-codec-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-codec-http/4/netty-codec-http-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-codec-http2/4/netty-codec-http2-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-common/4/netty-common-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-handler/4/netty-handler-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-resolver/4/netty-resolver-4.jar + - name: $MAVEN_REPOSITORY$/io/netty/netty-transport/4/netty-transport-4.jar + reason: withProjectLibrary - name: lib/sa-jdwp.jar \ No newline at end of file diff --git a/jps/jps-builders-6/intellij.platform.jps.build.javac.rt.iml b/jps/jps-builders-6/intellij.platform.jps.build.javac.rt.iml index 4c2558e26fbf..56f31c6e918e 100644 --- a/jps/jps-builders-6/intellij.platform.jps.build.javac.rt.iml +++ b/jps/jps-builders-6/intellij.platform.jps.build.javac.rt.iml @@ -10,11 +10,9 @@ - - - + \ No newline at end of file diff --git a/jps/jps-builders/intellij.platform.jps.build.iml b/jps/jps-builders/intellij.platform.jps.build.iml index 3035ac91fdc4..ec8a7bd8e12b 100644 --- a/jps/jps-builders/intellij.platform.jps.build.iml +++ b/jps/jps-builders/intellij.platform.jps.build.iml @@ -40,7 +40,6 @@ - @@ -63,7 +62,6 @@ - @@ -72,8 +70,8 @@ - + \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java index 7509265b2b12..b58cdd581da4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java @@ -18,12 +18,6 @@ import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.util.SystemProperties; import com.jgoodies.forms.layout.CellConstraints; import com.thoughtworks.qdox.JavaProjectBuilder; -import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.EventLoopGroup; -import io.netty.handler.codec.ByteToMessageDecoder; -import io.netty.handler.codec.protobuf.ProtobufDecoder; -import io.netty.resolver.AddressResolverGroup; -import io.netty.util.NetUtil; import kotlinx.metadata.jvm.JvmMetadataUtil; import net.n3.nanoxml.IXMLBuilder; import org.h2.mvstore.MVStore; @@ -42,8 +36,10 @@ import org.jetbrains.jps.model.serialization.JpsProjectLoader; import org.jetbrains.org.objectweb.asm.ClassVisitor; import org.jetbrains.org.objectweb.asm.ClassWriter; -import javax.tools.*; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; import java.io.File; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; @@ -56,12 +52,14 @@ public final class ClasspathBootstrap { private ClasspathBootstrap() { } private static final Class[] COMMON_REQUIRED_CLASSES = { - NetUtil.class, // netty common - EventLoopGroup.class, // netty transport - AddressResolverGroup.class, // netty resolver - ByteBufAllocator.class, // netty buffer - ByteToMessageDecoder.class, // netty codec http - ProtobufDecoder.class, // netty codec protobuf + // Uncomment to use the same netty that is used in the rest of IDE + //NetUtil.class, // netty common + //EventLoopGroup.class, // netty transport + //AddressResolverGroup.class, // netty resolver + //ByteBufAllocator.class, // netty buffer + //ByteToMessageDecoder.class, // netty codec http + //ProtobufDecoder.class, // netty codec protobuf + Message.class, // protobuf }; @@ -82,7 +80,36 @@ public final class ClasspathBootstrap { "jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED" }; - private static void addToClassPath(Class aClass, Set result) { + private static final String DEFAULT_MAVEN_REPOSITORY_PATH = ".m2/repository"; + private static final String NETTY_JPS_VERSION = "4.1.115.Final"; + private static final String NETTY_JPS_DISTRIBUTION_JAR_NAME = "netty-jps.jar"; + private static final String[] NETTY_ARTIFACT_NAMES = { + "netty-buffer", "netty-codec-http", "netty-codec-http2", "netty-codec", "netty-common", "netty-handler", "netty-resolver", "netty-transport" + }; + + private static void getNettyForJpsClasspath(Consumer consumer) { + Path rootPath = Path.of(getResourcePath(ExternalJavacProcess.class)); + Path nettyDistributionPath = rootPath.resolveSibling("rt").resolve(NETTY_JPS_DISTRIBUTION_JAR_NAME); + if (Files.isRegularFile(rootPath) && Files.exists(nettyDistributionPath)) { + // running regular installation + consumer.accept(nettyDistributionPath); + } + else { + // running from sources or on the build server + // take the library from the local maven repository + Path artifactRoot = getMavenLocalRepositoryDir().resolve("io").resolve("netty"); + for (String artifactName : NETTY_ARTIFACT_NAMES) { + consumer.accept(artifactRoot.resolve(artifactName).resolve(NETTY_JPS_VERSION).resolve(artifactName + "-" + NETTY_JPS_VERSION + ".jar")); + } + } + } + + private static @NotNull Path getMavenLocalRepositoryDir() { + final String userHome = System.getProperty("user.home", null); + return userHome != null ? Path.of(userHome, DEFAULT_MAVEN_REPOSITORY_PATH) : Path.of(DEFAULT_MAVEN_REPOSITORY_PATH); + } + + private static void addToClassPath(Set result, Class aClass) { Path path = PathManager.getJarForClass(aClass); if (path == null) { return; @@ -99,7 +126,7 @@ public final class ClasspathBootstrap { private static void addToClassPath(Set cp, @NotNull Class @NotNull [] classes) { for (Class aClass : classes) { - addToClassPath(aClass, cp); + addToClassPath(cp, aClass); } } @@ -107,42 +134,43 @@ public final class ClasspathBootstrap { // predictable order Set cp = new LinkedHashSet<>(); - addToClassPath(BuildMain.class, cp); - addToClassPath(ExternalJavacProcess.class, cp); // intellij.platform.jps.build.javac.rt part - addToClassPath(JavacReferenceCollector.class, cp); // jps-javac-extension library + addToClassPath(cp, BuildMain.class); + addToClassPath(cp, ExternalJavacProcess.class); // intellij.platform.jps.build.javac.rt part + addToClassPath(cp, JavacReferenceCollector.class); // jps-javac-extension library // intellij.platform.util addToClassPath(cp, ClassPathUtil.getUtilClasses()); ClassPathUtil.addKotlinStdlib(cp); - addToClassPath(JvmMetadataUtil.class, cp); // kotlin metadata parsing + addToClassPath(cp, JvmMetadataUtil.class); // kotlin metadata parsing addToClassPath(cp, COMMON_REQUIRED_CLASSES); + getNettyForJpsClasspath(path -> cp.add(path.toString())); - addToClassPath(ClassWriter.class, cp); // asm - addToClassPath(ClassVisitor.class, cp); // asm-commons - addToClassPath(RuntimeModuleRepository.class, cp); // intellij.platform.runtime.repository - addToClassPath(JpsModel.class, cp); // intellij.platform.jps.model - addToClassPath(JpsModelImpl.class, cp); // intellij.platform.jps.model.impl - addToClassPath(JpsProjectLoader.class, cp); // intellij.platform.jps.model.serialization - addToClassPath(AlienFormFileException.class, cp); // intellij.java.guiForms.compiler - addToClassPath(GridConstraints.class, cp); // intellij.java.guiForms.rt - addToClassPath(CellConstraints.class, cp); // jGoodies-forms + addToClassPath(cp, ClassWriter.class); // asm + addToClassPath(cp, ClassVisitor.class); // asm-commons + addToClassPath(cp, RuntimeModuleRepository.class); // intellij.platform.runtime.repository + addToClassPath(cp, JpsModel.class); // intellij.platform.jps.model + addToClassPath(cp, JpsModelImpl.class); // intellij.platform.jps.model.impl + addToClassPath(cp, JpsProjectLoader.class); // intellij.platform.jps.model.serialization + addToClassPath(cp, AlienFormFileException.class); // intellij.java.guiForms.compiler + addToClassPath(cp, GridConstraints.class); // intellij.java.guiForms.rt + addToClassPath(cp, CellConstraints.class); // jGoodies-forms cp.addAll(getInstrumentationUtilRoots()); - addToClassPath(IXMLBuilder.class, cp); // nano-xml - addToClassPath(JavaProjectBuilder.class, cp); // QDox lightweight java parser - addToClassPath(Gson.class, cp); // gson + addToClassPath(cp, IXMLBuilder.class); // nano-xml + addToClassPath(cp, JavaProjectBuilder.class); // QDox lightweight java parser + addToClassPath(cp, Gson.class); // gson // caffeine - addToClassPath(Caffeine.class, cp); + addToClassPath(cp, Caffeine.class); // Hashing - addToClassPath(Hashing.class, cp); - addToClassPath(MVStore.class, cp); + addToClassPath(cp, Hashing.class); + addToClassPath(cp, MVStore.class); addToClassPath(cp, ArtifactRepositoryManager.getClassesFromDependencies()); - addToClassPath(Tracer.class, cp); // tracing infrastructure + addToClassPath(cp, Tracer.class); // tracing infrastructure try { Class cmdLineWrapper = Class.forName("com.intellij.rt.execution.CommandLineWrapper"); - addToClassPath(cmdLineWrapper, cp); // idea_rt.jar + addToClassPath(cp, cmdLineWrapper); // idea_rt.jar } catch (Throwable ignored) { } @@ -159,7 +187,7 @@ public final class ClasspathBootstrap { } public static List getExternalJavacProcessClasspath(String sdkHome, JavaCompilingTool compilingTool) { - // Important! All dependencies must be java 6 compatible (the oldest supported javac to be launched) + // Important! All dependencies must be java 7 compatible (the oldest supported javac to be launched) final Set cp = new LinkedHashSet<>(); cp.add(getResourceFile(ExternalJavacProcess.class)); // self cp.add(getResourceFile(JavacReferenceCollector.class)); // jps-javac-extension library @@ -168,6 +196,7 @@ public final class ClasspathBootstrap { for (Class aClass : COMMON_REQUIRED_CLASSES) { cp.add(getResourceFile(aClass)); } + getNettyForJpsClasspath(path -> cp.add(path.toFile())); try { final Class cmdLineWrapper = Class.forName("com.intellij.rt.execution.CommandLineWrapper"); diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/BytecodeCompatibilityTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/BytecodeCompatibilityTest.java new file mode 100644 index 000000000000..dcbf64befa15 --- /dev/null +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/BytecodeCompatibilityTest.java @@ -0,0 +1,89 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.ether; + +import com.google.gson.Gson; +import com.intellij.compiler.instrumentation.FailSafeClassReader; +import com.intellij.compiler.instrumentation.InstrumenterClassWriter; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.util.SystemInfoRt; +import com.intellij.psi.impl.compiled.ClsParsingUtil; +import com.intellij.util.SystemProperties; +import org.jetbrains.jps.builders.JpsBuildTestCase; +import org.jetbrains.jps.builders.impl.java.JavacCompilerTool; +import org.jetbrains.jps.cmdline.BuildMain; +import org.jetbrains.jps.cmdline.ClasspathBootstrap; +import org.jetbrains.jps.javac.ExternalJavacProcess; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.org.objectweb.asm.ClassWriter; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class BytecodeCompatibilityTest extends JpsBuildTestCase { + private static final int MIN_REQUIRED_JPS_BUILD_RUNTIME_VERSION = 11; + private static final int MIN_REQUIRED_EXTERNAL_JAVAC_RUNTIME_VERSION = ExternalJavacProcess.MINIMUM_REQUIRED_JAVA_VERSION; + + public void testJpsBytecode() throws IOException { + + List classpath = new ArrayList<>(); + for (String path : ClasspathBootstrap.getBuildProcessApplicationClasspath()) { + classpath.add(new File(path).toURI().toURL()); + } + + ensureBytecodeVersion(List.of( + + BuildMain.class.getName(), // JPS Build + ClassWriter.class.getName(), // ASM + JpsModel.class.getName(), // JPS Model + Gson.class.getName() + + ), MIN_REQUIRED_JPS_BUILD_RUNTIME_VERSION, classpath); + } + + public void testForkedJavacBytecode() throws IOException { + + List classpath = new ArrayList<>(); + for (File file : ClasspathBootstrap.getExternalJavacProcessClasspath(SystemProperties.getJavaHome(), new JavacCompilerTool())) { + classpath.add(file.toURI().toURL()); + } + + ensureBytecodeVersion(List.of( + ExternalJavacProcess.class.getName(), + "com.google.protobuf.Message", // protobuf + "io.netty.util.NetUtil", // netty common + "io.netty.channel.EventLoopGroup", // netty transport + "io.netty.resolver.AddressResolverGroup", // netty resolver + "io.netty.buffer.ByteBufAllocator", // netty buffer + "io.netty.handler.codec.ByteToMessageDecoder", // netty codec http + "io.netty.handler.codec.protobuf.ProtobufDecoder", // netty codec protobuf + "org.jetbrains.jps.javac.ast.JavacReferenceCollector", // reference collector + SystemInfoRt.class.getName() // util_rt + + ), MIN_REQUIRED_EXTERNAL_JAVAC_RUNTIME_VERSION, classpath); + } + + protected void ensureBytecodeVersion(List classesToCheck, int maxJavaVersionFeatureLevel, Collection classpath) throws IOException { + + try (URLClassLoader loader = new URLClassLoader(classpath.toArray(URL[]::new), null)) { + for (String clsName : classesToCheck) { + try (InputStream stream = loader.getResourceAsStream(clsName.replace('.', '/') + ".class")) { + assertNotNull("Required class " + clsName + " is not found in the classpath of the external javac process", stream); + + int majorBytecodeVersion = InstrumenterClassWriter.getClassFileVersion(new FailSafeClassReader(stream)); + + JavaSdkVersion targetSdkVersion = ClsParsingUtil.getJdkVersionByBytecode(majorBytecodeVersion); + assertNotNull(targetSdkVersion); + + assertTrue("Maximum allowed bytecode version for class " + clsName + " in the classpath of external javac process is " + maxJavaVersionFeatureLevel + " actual version is " + majorBytecodeVersion, targetSdkVersion.getMaxLanguageLevel().feature() <= maxJavaVersionFeatureLevel); + } + } + } + } + +} diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/JavaPluginLayout.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/JavaPluginLayout.kt index d84bb4095309..61f609585cd3 100644 --- a/platform/build-scripts/src/org/jetbrains/intellij/build/JavaPluginLayout.kt +++ b/platform/build-scripts/src/org/jetbrains/intellij/build/JavaPluginLayout.kt @@ -15,7 +15,7 @@ object JavaPluginLayout { spec.excludeFromModule("intellij.java.resources.en", "search/searchableOptions.xml") - spec.withProjectLibrary("netty-codec-protobuf", "netty-codec-protobuf.jar") + spec.withProjectLibrary("netty-jps", "rt/netty-jps.jar") spec.withModule("intellij.platform.jps.build.launcher", "jps-launcher.jar") spec.withModule("intellij.platform.jps.build", "jps-builders.jar")