From 43c7029e03b8745aff5b37418a145526c67a05dc Mon Sep 17 00:00:00 2001 From: Bastien JANSEN Date: Mon, 25 Nov 2024 07:25:04 +0100 Subject: [PATCH 1/7] add a release pipeline --- .github/workflows/release.yml | 35 +++++++++++++++++++++++++++++++++++ build.gradle | 12 ++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..912ef77 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: Release CI + +on: + release: + types: + - published + +jobs: + build: + + runs-on: ubuntu-latest + + + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: 11 + distribution: temurin + + - name: Build with Gradle + run: | + ./gradlew -PideaVersion=${IDEA_VERSION} check buildPlugin + env: + - IDEA_VERSION: IC-2020.3 + + - name: Publish to Sonatype + env: + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + run: ./gradlew publish -PossrhToken="${SONATYPE_USERNAME}" -PossrhTokenPassword="${SONATYPE_PASSWORD}" -PsigningKey="${SIGNING_KEY}" -PsigningPassword="${SIGNING_PASSWORD}" diff --git a/build.gradle b/build.gradle index 470cea9..5fe47a0 100644 --- a/build.gradle +++ b/build.gradle @@ -22,8 +22,8 @@ apply plugin: 'java' apply plugin: 'org.jetbrains.intellij' compileJava { - sourceCompatibility = '17' - targetCompatibility = '17' + sourceCompatibility = '11' + targetCompatibility = '11' } intellij { @@ -40,7 +40,7 @@ repositories { dependencies { implementation("org.antlr:antlr4-runtime:$antlr4Version") { - exclude group:'com.ibm.icu', module:'icu4j' + exclude group: 'com.ibm.icu', module: 'icu4j' } antlr "org.antlr:antlr4:$antlr4Version" } @@ -97,8 +97,8 @@ publishing { maven { url "https://oss.sonatype.org/${libraryVersion.contains("-SNAPSHOT") ? 'content/repositories/snapshots' : 'service/local/staging/deploy/maven2'}" credentials { - username = findProperty("ossrhToken") as String - password = findProperty("ossrhTokenPassword") as String + username = findProperty("ossrhToken") as String + password = findProperty("ossrhTokenPassword") as String } } } @@ -110,7 +110,7 @@ signing { javadoc { - if(JavaVersion.current().isJava9Compatible()) { + if (JavaVersion.current().isJava9Compatible()) { options.addBooleanOption('html5', true) } } From 4e1f2b97eab13fb157b065d43ee27fced5254686 Mon Sep 17 00:00:00 2001 From: Bastien JANSEN Date: Mon, 25 Nov 2024 07:30:07 +0100 Subject: [PATCH 2/7] configure signature for releases --- build.gradle | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 5fe47a0..6a05a26 100644 --- a/build.gradle +++ b/build.gradle @@ -105,10 +105,15 @@ publishing { } signing { - sign publishing.publications.maven + afterEvaluate { project -> + required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } + def signingKey = findProperty("signingKey") + def signingPassword = findProperty("signingPassword") + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.mavenJava + } } - javadoc { if (JavaVersion.current().isJava9Compatible()) { options.addBooleanOption('html5', true) From 9ed002565026291e017dc9d8e0259304945d0ba2 Mon Sep 17 00:00:00 2001 From: Bastien JANSEN Date: Mon, 25 Nov 2024 07:34:48 +0100 Subject: [PATCH 3/7] add explicit dependency to JUnit, which is not bundled anymore in 2024.3 --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6a05a26..11d057f 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,8 @@ dependencies { exclude group: 'com.ibm.icu', module: 'icu4j' } antlr "org.antlr:antlr4:$antlr4Version" + + testImplementation("junit:junit:4.13.2") } task sourcesJar(type: Jar) { @@ -110,7 +112,7 @@ signing { def signingKey = findProperty("signingKey") def signingPassword = findProperty("signingPassword") useInMemoryPgpKeys(signingKey, signingPassword) - sign publishing.publications.mavenJava + sign publishing.publications.maven } } From bca82a65ec1c423fb1abc909b254eebb2d305d50 Mon Sep 17 00:00:00 2001 From: Bastien JANSEN Date: Mon, 25 Nov 2024 07:54:09 +0100 Subject: [PATCH 4/7] add explicit dependency to JUnit, which is not bundled anymore in 2024.3 --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 11d057f..46b5857 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,7 @@ dependencies { antlr "org.antlr:antlr4:$antlr4Version" testImplementation("junit:junit:4.13.2") + testImplementation("org.opentest4j:opentest4j:1.3.0") } task sourcesJar(type: Jar) { From c6246ad4ea6b0e4c336013d0d108bba62bec87ca Mon Sep 17 00:00:00 2001 From: l-Luna Date: Tue, 10 Dec 2024 22:48:30 +0000 Subject: [PATCH 5/7] Programmatic test cases --- .../adaptor/test/testcases}/Issue2.g4 | 4 +- src/test/java/issue2/Issue2FileType.java | 40 ------ src/test/java/issue2/Issue2Language.java | 12 -- .../java/issue2/Issue2ParserDefinition.java | 85 ------------- src/test/java/issue2/Issue2ParserTest.java | 19 --- .../intellij/adaptor/test/AntlrTestCase.java | 44 +++++++ .../intellij/adaptor/test/TestFileType.java | 35 ++++++ .../intellij/adaptor/test/TestLanguage.java | 59 +++++++++ .../adaptor/test/TestParserDefinition.java | 116 ++++++++++++++++++ .../issue2.ext => Issue2/issue2.Issue2} | 0 .../testData/{issue2 => Issue2}/issue2.txt | 0 11 files changed, 256 insertions(+), 158 deletions(-) rename src/test/antlr/{issue2 => org/antlr/intellij/adaptor/test/testcases}/Issue2.g4 (69%) delete mode 100644 src/test/java/issue2/Issue2FileType.java delete mode 100644 src/test/java/issue2/Issue2Language.java delete mode 100644 src/test/java/issue2/Issue2ParserDefinition.java delete mode 100644 src/test/java/issue2/Issue2ParserTest.java create mode 100644 src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java create mode 100644 src/test/java/org/antlr/intellij/adaptor/test/TestFileType.java create mode 100644 src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java create mode 100644 src/test/java/org/antlr/intellij/adaptor/test/TestParserDefinition.java rename src/test/resources/testData/{issue2/issue2.ext => Issue2/issue2.Issue2} (100%) rename src/test/resources/testData/{issue2 => Issue2}/issue2.txt (100%) diff --git a/src/test/antlr/issue2/Issue2.g4 b/src/test/antlr/org/antlr/intellij/adaptor/test/testcases/Issue2.g4 similarity index 69% rename from src/test/antlr/issue2/Issue2.g4 rename to src/test/antlr/org/antlr/intellij/adaptor/test/testcases/Issue2.g4 index 5a69779..219b37c 100644 --- a/src/test/antlr/issue2/Issue2.g4 +++ b/src/test/antlr/org/antlr/intellij/adaptor/test/testcases/Issue2.g4 @@ -1,7 +1,7 @@ grammar Issue2; @header { -package org.antlr.intellij.adaptor.issue2; +package org.antlr.intellij.adaptor.test.testcases; } block @@ -15,4 +15,4 @@ usesList ; ID: [a-zA-Z]+; -WS: [\t\r\n ]+ -> skip; +WS: [\t\r\n ]+ -> skip; \ No newline at end of file diff --git a/src/test/java/issue2/Issue2FileType.java b/src/test/java/issue2/Issue2FileType.java deleted file mode 100644 index b22238e..0000000 --- a/src/test/java/issue2/Issue2FileType.java +++ /dev/null @@ -1,40 +0,0 @@ -package issue2; - -import com.intellij.openapi.fileTypes.LanguageFileType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -class Issue2FileType extends LanguageFileType { - - static Issue2FileType INSTANCE = new Issue2FileType(); - - private Issue2FileType() { - super(Issue2Language.INSTANCE); - } - - @NotNull - @Override - public String getName() { - return "Issue 2"; - } - - @NotNull - @Override - public String getDescription() { - return "Issue 2"; - } - - @NotNull - @Override - public String getDefaultExtension() { - return "ext"; - } - - @Nullable - @Override - public Icon getIcon() { - return null; - } -} diff --git a/src/test/java/issue2/Issue2Language.java b/src/test/java/issue2/Issue2Language.java deleted file mode 100644 index 6c0d939..0000000 --- a/src/test/java/issue2/Issue2Language.java +++ /dev/null @@ -1,12 +0,0 @@ -package issue2; - -import com.intellij.lang.Language; - -class Issue2Language extends Language { - - static Issue2Language INSTANCE = new Issue2Language(); - - private Issue2Language() { - super("Issue2"); - } -} diff --git a/src/test/java/issue2/Issue2ParserDefinition.java b/src/test/java/issue2/Issue2ParserDefinition.java deleted file mode 100644 index a9cd827..0000000 --- a/src/test/java/issue2/Issue2ParserDefinition.java +++ /dev/null @@ -1,85 +0,0 @@ -package issue2; - -import com.intellij.extapi.psi.PsiFileBase; -import com.intellij.lang.ASTNode; -import com.intellij.lang.ParserDefinition; -import com.intellij.lang.PsiParser; -import com.intellij.lexer.Lexer; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.project.Project; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.IFileElementType; -import com.intellij.psi.tree.TokenSet; -import org.antlr.intellij.adaptor.issue2.Issue2Lexer; -import org.antlr.intellij.adaptor.issue2.Issue2Parser; -import org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor; -import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory; -import org.antlr.intellij.adaptor.parser.ANTLRParserAdaptor; -import org.antlr.intellij.adaptor.psi.ANTLRPsiNode; -import org.antlr.v4.runtime.Parser; -import org.antlr.v4.runtime.tree.ParseTree; -import org.jetbrains.annotations.NotNull; - -public class Issue2ParserDefinition implements ParserDefinition { - - public Issue2ParserDefinition() { - PSIElementTypeFactory.defineLanguageIElementTypes( - Issue2Language.INSTANCE, - Issue2Lexer.VOCABULARY, - Issue2Parser.ruleNames - ); - } - - @NotNull - @Override - public Lexer createLexer(Project project) { - return new ANTLRLexerAdaptor(Issue2Language.INSTANCE, new Issue2Lexer(null)); - } - - @Override - public PsiParser createParser(Project project) { - return new ANTLRParserAdaptor(Issue2Language.INSTANCE, new Issue2Parser(null)) { - @Override - protected ParseTree parse(Parser parser, IElementType root) { - return ((Issue2Parser) parser).block(); - } - }; - } - - @Override - public IFileElementType getFileNodeType() { - return new IFileElementType(Issue2Language.INSTANCE); - } - - @NotNull - @Override - public TokenSet getCommentTokens() { - return TokenSet.EMPTY; - } - - @NotNull - @Override - public TokenSet getStringLiteralElements() { - return TokenSet.EMPTY; - } - - @NotNull - @Override - public PsiElement createElement(ASTNode node) { - return new ANTLRPsiNode(node); - } - - @Override - public PsiFile createFile(FileViewProvider viewProvider) { - return new PsiFileBase(viewProvider, Issue2Language.INSTANCE) { - @NotNull - @Override - public FileType getFileType() { - return Issue2FileType.INSTANCE; - } - }; - } -} diff --git a/src/test/java/issue2/Issue2ParserTest.java b/src/test/java/issue2/Issue2ParserTest.java deleted file mode 100644 index 5d33890..0000000 --- a/src/test/java/issue2/Issue2ParserTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package issue2; - -import com.intellij.testFramework.ParsingTestCase; - -public class Issue2ParserTest extends ParsingTestCase { - - public Issue2ParserTest() { - super("issue2", "ext", true, new Issue2ParserDefinition()); - } - - public void testIssue2() { - doTest(true); - } - - @Override - protected String getTestDataPath() { - return "src/test/resources/testData"; - } -} diff --git a/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java b/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java new file mode 100644 index 0000000..e950ef3 --- /dev/null +++ b/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java @@ -0,0 +1,44 @@ +package org.antlr.intellij.adaptor.test; + +import com.intellij.lang.Language; +import com.intellij.testFramework.ParsingTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; + +@RunWith(Parameterized.class) +public class AntlrTestCase extends ParsingTestCase{ + + private final String name; + + @Parameterized.Parameters(name = "{index}: {2} for {0}/{1}") + public static Iterable parameters(){ + return Arrays.asList((Object[]) new Object[][]{ + { "Issue2", "block", "issue2" } + }); + } + + public AntlrTestCase(String lang, String root, String name){ + this(lang, root, name, TestLanguage.synthesizeTestLanguage(lang)); + } + + private AntlrTestCase(String lang, String root, String name, Language language){ + super(lang, lang, TestParserDefinition.byName(lang, root, language, new TestFileType(lang, language))); + this.name = name; + } + + public String getName(){ + return name; + } + + protected String getTestDataPath(){ + return "src/test/resources/testData"; + } + + @Test + public void test(){ + doTest(true); + } +} \ No newline at end of file diff --git a/src/test/java/org/antlr/intellij/adaptor/test/TestFileType.java b/src/test/java/org/antlr/intellij/adaptor/test/TestFileType.java new file mode 100644 index 0000000..6c7c4ea --- /dev/null +++ b/src/test/java/org/antlr/intellij/adaptor/test/TestFileType.java @@ -0,0 +1,35 @@ +package org.antlr.intellij.adaptor.test; + +import com.intellij.lang.Language; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.util.NlsContexts; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class TestFileType extends LanguageFileType{ + + private final String name; + + public TestFileType(String name, Language language){ + super(language); + this.name = name; + } + + public @NonNls @NotNull String getName(){ + return name; + } + + public @NlsContexts.Label @NotNull String getDescription(){ + return name; + } + + public @NotNull String getDefaultExtension(){ + return name; + } + + public Icon getIcon(){ + return null; + } +} \ No newline at end of file diff --git a/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java b/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java new file mode 100644 index 0000000..33cab00 --- /dev/null +++ b/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java @@ -0,0 +1,59 @@ +package org.antlr.intellij.adaptor.test; + +import com.intellij.lang.Language; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.org.objectweb.asm.ClassWriter; +import org.jetbrains.org.objectweb.asm.MethodVisitor; +import org.jetbrains.org.objectweb.asm.Opcodes; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationTargetException; + +/** + * A generic class for testing languages. Note that multiple instances of a language class cannot be used + * and will be rejected by the IntelliJ runtime; instead, a subclass must be generated for each test case, + * hence the abstract label. + */ +public abstract class TestLanguage extends Language{ + + protected TestLanguage(@NonNls @NotNull String lang){ + super(lang); + } + + /** + * Generates a new subclass of {@linkplain TestLanguage}, and returns the canonical instance. + */ + public static TestLanguage synthesizeTestLanguage(@NotNull String lang){ + // Create a subclass of TestLanguage... + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + writer.visit( + Opcodes.V1_8, + Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC, + "org/antlr/intellij/adaptor/test/$Lang" + lang, + "", + "org/antlr/intellij/adaptor/test/TestLanguage", + new String[0] + ); + + // ...with one constructor that takes 0 parameters and has no type variables... + MethodVisitor ctor = writer.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", "", new String[0]); + ctor.visitCode(); + // ...that invokes the super constructor with itself and the language name... + ctor.visitVarInsn(Opcodes.ALOAD, 0); + ctor.visitLdcInsn(lang); + ctor.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/antlr/intellij/adaptor/test/TestLanguage", "", "(Ljava/lang/String;)V", false); + ctor.visitInsn(Opcodes.RETURN); + ctor.visitMaxs(0, 0); + ctor.visitEnd(); + writer.visitEnd(); + + try{ + // ...then define this class and return one instance. + Class cls = MethodHandles.lookup().defineClass(writer.toByteArray()); + return (TestLanguage)cls.getConstructor().newInstance(); + }catch(IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e){ + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/antlr/intellij/adaptor/test/TestParserDefinition.java b/src/test/java/org/antlr/intellij/adaptor/test/TestParserDefinition.java new file mode 100644 index 0000000..6d61d11 --- /dev/null +++ b/src/test/java/org/antlr/intellij/adaptor/test/TestParserDefinition.java @@ -0,0 +1,116 @@ +package org.antlr.intellij.adaptor.test; + +import com.intellij.extapi.psi.PsiFileBase; +import com.intellij.lang.ASTNode; +import com.intellij.lang.Language; +import com.intellij.lang.ParserDefinition; +import com.intellij.lang.PsiParser; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.IFileElementType; +import com.intellij.psi.tree.TokenSet; +import org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor; +import org.antlr.intellij.adaptor.lexer.PSIElementTypeFactory; +import org.antlr.intellij.adaptor.parser.ANTLRParserAdaptor; +import org.antlr.intellij.adaptor.psi.ANTLRPsiNode; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.ParseTree; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class TestParserDefinition implements ParserDefinition{ + + private final Class parserClass; + private final Class lexerClass; + private final Method rootNodeParser; + private final Language language; + private final FileType fileType; + + public TestParserDefinition(Class parserClass, Class lexerClass, Method parser, Language language, FileType fileType){ + this.parserClass = parserClass; + this.lexerClass = lexerClass; + rootNodeParser = parser; + this.language = language; + this.fileType = fileType; + + try{ + PSIElementTypeFactory.defineLanguageIElementTypes( + language, + (Vocabulary)lexerClass.getDeclaredField("VOCABULARY").get(null), + (String[])parserClass.getDeclaredField("ruleNames").get(null) + ); + }catch(IllegalAccessException | NoSuchFieldException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public static TestParserDefinition byName(String name, String root, Language language, FileType fileType){ + try{ + Class parserClass = Class.forName("org.antlr.intellij.adaptor.test.testcases." + name + "Parser"); + Class lexerClass = Class.forName("org.antlr.intellij.adaptor.test.testcases." + name + "Lexer"); + if(!Parser.class.isAssignableFrom(parserClass) || !Lexer.class.isAssignableFrom(lexerClass)) + throw new IllegalArgumentException("Given parser/lexer class doesn't exist, or is invalid"); + Method rootNodeParser = parserClass.getDeclaredMethod(root); + if(!ParseTree.class.isAssignableFrom(rootNodeParser.getReturnType())) + throw new IllegalArgumentException("Given root node method is not a parser"); + return new TestParserDefinition((Class)parserClass, (Class)lexerClass, rootNodeParser, language, fileType); + }catch(ReflectiveOperationException e){ + throw new RuntimeException(e); + } + } + + public @NotNull com.intellij.lexer.Lexer createLexer(Project project){ + try{ + return new ANTLRLexerAdaptor(language, lexerClass.getConstructor(CharStream.class).newInstance((Object)null)); + }catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e){ + throw new RuntimeException(e); + } + } + + public @NotNull PsiParser createParser(Project project){ + try{ + return new ANTLRParserAdaptor(language, parserClass.getConstructor(TokenStream.class).newInstance((Object)null)){ + protected ParseTree parse(org.antlr.v4.runtime.Parser parser, IElementType root){ + try{ + return (ParseTree)rootNodeParser.invoke(parser); + }catch(IllegalAccessException | InvocationTargetException e){ + throw new RuntimeException(e); + } + } + }; + }catch(NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e){ + throw new RuntimeException(e); + } + } + + public @NotNull IFileElementType getFileNodeType(){ + return new IFileElementType(language); + } + + public @NotNull TokenSet getCommentTokens(){ + return TokenSet.EMPTY; + } + + public @NotNull TokenSet getStringLiteralElements(){ + return TokenSet.EMPTY; + } + + public @NotNull PsiElement createElement(ASTNode node){ + return new ANTLRPsiNode(node); + } + + public @NotNull PsiFile createFile(@NotNull FileViewProvider viewProvider){ + return new PsiFileBase(viewProvider, language){ + public @NotNull FileType getFileType(){ + return fileType; + } + }; + } +} \ No newline at end of file diff --git a/src/test/resources/testData/issue2/issue2.ext b/src/test/resources/testData/Issue2/issue2.Issue2 similarity index 100% rename from src/test/resources/testData/issue2/issue2.ext rename to src/test/resources/testData/Issue2/issue2.Issue2 diff --git a/src/test/resources/testData/issue2/issue2.txt b/src/test/resources/testData/Issue2/issue2.txt similarity index 100% rename from src/test/resources/testData/issue2/issue2.txt rename to src/test/resources/testData/Issue2/issue2.txt From b3f42dfab571cd769d2ce878a1be2ec5937d4945 Mon Sep 17 00:00:00 2001 From: l-Luna Date: Tue, 10 Dec 2024 22:56:41 +0000 Subject: [PATCH 6/7] fix test cases that reuse the same language --- .../antlr/intellij/adaptor/test/AntlrTestCase.java | 3 ++- .../antlr/intellij/adaptor/test/TestLanguage.java | 5 +++-- .../resources/testData/Issue2/straightforward.Issue2 | 3 +++ .../resources/testData/Issue2/straightforward.txt | 12 ++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/test/resources/testData/Issue2/straightforward.Issue2 create mode 100644 src/test/resources/testData/Issue2/straightforward.txt diff --git a/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java b/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java index e950ef3..3695ba4 100644 --- a/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java +++ b/src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java @@ -16,7 +16,8 @@ public class AntlrTestCase extends ParsingTestCase{ @Parameterized.Parameters(name = "{index}: {2} for {0}/{1}") public static Iterable parameters(){ return Arrays.asList((Object[]) new Object[][]{ - { "Issue2", "block", "issue2" } + { "Issue2", "block", "issue2" }, + { "Issue2", "block", "straightforward" } }); } diff --git a/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java b/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java index 33cab00..b8717c3 100644 --- a/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java +++ b/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java @@ -27,10 +27,11 @@ protected TestLanguage(@NonNls @NotNull String lang){ public static TestLanguage synthesizeTestLanguage(@NotNull String lang){ // Create a subclass of TestLanguage... ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + long l = System.currentTimeMillis(); writer.visit( Opcodes.V1_8, Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC, - "org/antlr/intellij/adaptor/test/$Lang" + lang, + "org/antlr/intellij/adaptor/test/$Lang" + lang + "@" + l, "", "org/antlr/intellij/adaptor/test/TestLanguage", new String[0] @@ -41,7 +42,7 @@ public static TestLanguage synthesizeTestLanguage(@NotNull String lang){ ctor.visitCode(); // ...that invokes the super constructor with itself and the language name... ctor.visitVarInsn(Opcodes.ALOAD, 0); - ctor.visitLdcInsn(lang); + ctor.visitLdcInsn(lang + "@" + l); ctor.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/antlr/intellij/adaptor/test/TestLanguage", "", "(Ljava/lang/String;)V", false); ctor.visitInsn(Opcodes.RETURN); ctor.visitMaxs(0, 0); diff --git a/src/test/resources/testData/Issue2/straightforward.Issue2 b/src/test/resources/testData/Issue2/straightforward.Issue2 new file mode 100644 index 0000000..2656fe3 --- /dev/null +++ b/src/test/resources/testData/Issue2/straightforward.Issue2 @@ -0,0 +1,3 @@ +start X; + uses Nothing; +end X; \ No newline at end of file diff --git a/src/test/resources/testData/Issue2/straightforward.txt b/src/test/resources/testData/Issue2/straightforward.txt new file mode 100644 index 0000000..c83ae5f --- /dev/null +++ b/src/test/resources/testData/Issue2/straightforward.txt @@ -0,0 +1,12 @@ +FILE + ANTLRPsiNode(block) + PsiElement('start')('start ') + PsiElement(ID)('X') + PsiElement(';')(';\n\t') + ANTLRPsiNode(usesList) + PsiElement('uses')('uses ') + PsiElement(ID)('Nothing') + PsiElement(';')(';\n') + PsiElement('end')('end ') + PsiElement(ID)('X') + PsiElement(';')(';') \ No newline at end of file From e9281f2a2b87184e4997a180eaefd4c9e616cc51 Mon Sep 17 00:00:00 2001 From: l-Luna Date: Wed, 11 Dec 2024 14:24:47 +0000 Subject: [PATCH 7/7] cache reused test languages --- .../antlr/intellij/adaptor/test/TestLanguage.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java b/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java index b8717c3..2cb8433 100644 --- a/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java +++ b/src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java @@ -9,6 +9,8 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; /** * A generic class for testing languages. Note that multiple instances of a language class cannot be used @@ -21,17 +23,22 @@ protected TestLanguage(@NonNls @NotNull String lang){ super(lang); } + private static final Map languageCache = new HashMap<>(); + /** * Generates a new subclass of {@linkplain TestLanguage}, and returns the canonical instance. */ public static TestLanguage synthesizeTestLanguage(@NotNull String lang){ + if(languageCache.containsKey(lang)) + return languageCache.get(lang); + // Create a subclass of TestLanguage... ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); long l = System.currentTimeMillis(); writer.visit( Opcodes.V1_8, Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC, - "org/antlr/intellij/adaptor/test/$Lang" + lang + "@" + l, + "org/antlr/intellij/adaptor/test/$Lang" + lang, "", "org/antlr/intellij/adaptor/test/TestLanguage", new String[0] @@ -42,7 +49,7 @@ public static TestLanguage synthesizeTestLanguage(@NotNull String lang){ ctor.visitCode(); // ...that invokes the super constructor with itself and the language name... ctor.visitVarInsn(Opcodes.ALOAD, 0); - ctor.visitLdcInsn(lang + "@" + l); + ctor.visitLdcInsn(lang); ctor.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/antlr/intellij/adaptor/test/TestLanguage", "", "(Ljava/lang/String;)V", false); ctor.visitInsn(Opcodes.RETURN); ctor.visitMaxs(0, 0); @@ -52,7 +59,9 @@ public static TestLanguage synthesizeTestLanguage(@NotNull String lang){ try{ // ...then define this class and return one instance. Class cls = MethodHandles.lookup().defineClass(writer.toByteArray()); - return (TestLanguage)cls.getConstructor().newInstance(); + TestLanguage language = (TestLanguage)cls.getConstructor().newInstance(); + languageCache.put(lang, language); + return language; }catch(IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e){ throw new RuntimeException(e); }