Improve RuleTst performance

Reuse the classloader for auxclasspath
instead of creating a new one for every
single rule test case.
This commit is contained in:
Andreas Dangel 2024-08-01 11:07:36 +02:00
parent d171bcbdb3
commit c53462b3b6
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
2 changed files with 18 additions and 36 deletions

View File

@ -6,16 +6,8 @@ package net.sourceforge.pmd.lang.java;
import static net.sourceforge.pmd.lang.ast.Parser.ParserTask; import static net.sourceforge.pmd.lang.ast.Parser.ParserTask;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.UncheckedIOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -29,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import net.sourceforge.pmd.internal.util.ClasspathClassLoader;
import net.sourceforge.pmd.lang.LanguageProcessor; import net.sourceforge.pmd.lang.LanguageProcessor;
import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.ast.SemanticErrorReporter;
@ -54,32 +47,15 @@ public class JavaParsingHelper extends BaseParsingHelper<JavaParsingHelper, ASTC
* default options of JavaParsingHelper. This allows constants like * default options of JavaParsingHelper. This allows constants like
* the null type to be compared. * the null type to be compared.
*/ */
public static final TypeSystem TEST_TYPE_SYSTEM = TypeSystem.usingClasspath(name -> { public static final TypeSystem TEST_TYPE_SYSTEM;
ClassLoader classLoader = JavaParsingHelper.class.getClassLoader();
if (name.endsWith("/module-info.class")) { static {
String moduleName = name.substring(0, name.length() - "/module-info.class".length()); try {
TEST_TYPE_SYSTEM = TypeSystem.usingClassLoaderClasspath(new ClasspathClassLoader("", JavaParsingHelper.class.getClassLoader()));
InputStream inputStream = null; } catch (IOException e) {
@SuppressWarnings("PMD.CloseResource") throw new RuntimeException(e);
// this JrtFileSystem instance can't be closed (UnsupportedOperationException),
// because it used by the current running JVM
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
try {
Path moduleInfoPath = fs.getPath("modules", moduleName, "module-info.class");
if (Files.exists(moduleInfoPath)) {
inputStream = new ByteArrayInputStream(Files.readAllBytes(moduleInfoPath));
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
if (inputStream != null) {
return inputStream;
}
} }
}
return classLoader.getResourceAsStream(name);
});
/** This runs all processing stages when parsing. */ /** This runs all processing stages when parsing. */
public static final JavaParsingHelper DEFAULT = new JavaParsingHelper( public static final JavaParsingHelper DEFAULT = new JavaParsingHelper(

View File

@ -31,6 +31,7 @@ import org.xml.sax.InputSource;
import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.PmdAnalysis; import net.sourceforge.pmd.PmdAnalysis;
import net.sourceforge.pmd.internal.util.ClasspathClassLoader;
import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.document.FileId; import net.sourceforge.pmd.lang.document.FileId;
import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextFile;
@ -225,9 +226,10 @@ public abstract class RuleTst {
return runTestFromString(test.getCode(), rule, test.getLanguageVersion()); return runTestFromString(test.getCode(), rule, test.getLanguageVersion());
} }
private static final Path PATH_TO_JRT_FS_JAR; private static final ClassLoader TEST_AUXCLASSPATH_CLASSLOADER;
static { static {
final Path PATH_TO_JRT_FS_JAR;
// find jrt-fs.jar to be added to auxclasspath // find jrt-fs.jar to be added to auxclasspath
// Similar logic like jdk.internal.jrtfs.SystemImage // Similar logic like jdk.internal.jrtfs.SystemImage
CodeSource codeSource = Object.class.getProtectionDomain().getCodeSource(); CodeSource codeSource = Object.class.getProtectionDomain().getCodeSource();
@ -244,6 +246,12 @@ public abstract class RuleTst {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
} }
try {
TEST_AUXCLASSPATH_CLASSLOADER = new ClasspathClassLoader(PATH_TO_JRT_FS_JAR.toString(), PMDConfiguration.class.getClassLoader());
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
/** /**
@ -254,9 +262,7 @@ public abstract class RuleTst {
configuration.setIgnoreIncrementalAnalysis(true); configuration.setIgnoreIncrementalAnalysis(true);
configuration.setDefaultLanguageVersion(languageVersion); configuration.setDefaultLanguageVersion(languageVersion);
configuration.setThreads(0); // don't use separate threads configuration.setThreads(0); // don't use separate threads
configuration.prependAuxClasspath("."); configuration.setClassLoader(TEST_AUXCLASSPATH_CLASSLOADER);
configuration.prependAuxClasspath(PATH_TO_JRT_FS_JAR.toString());
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) { try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
pmd.files().addFile(TextFile.forCharSeq(code, FileId.fromPathLikeString("file"), languageVersion)); pmd.files().addFile(TextFile.forCharSeq(code, FileId.fromPathLikeString("file"), languageVersion));