From 295bf079b9d1ae4bb5b441ea3a741b949ff9fa93 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Tue, 21 May 2024 12:14:12 +0200 Subject: [PATCH 01/12] Add continue and do-while, close #331 --- resources/bytecode/javFiles/While.jav | 9 ++++++++ .../de/dhbwstuttgart/bytecode/Codegen.java | 21 +++++++++++++++++++ .../StatementGenerator.java | 8 +++++-- .../syntaxtree/AbstractASTWalker.java | 5 +++++ .../syntaxtree/StatementVisitor.java | 2 ++ .../syntaxtree/statement/Continue.java | 18 ++++++++++++++++ .../syntaxtree/visual/OutputGenerator.java | 5 +++++ .../generate/StatementToTargetExpression.java | 7 ++++++- .../generate/TracingStatementVisitor.java | 5 +++++ .../target/tree/expression/TargetDo.java | 4 ++++ .../tree/expression/TargetExpression.java | 2 +- .../target/tree/expression/TargetWhile.java | 2 -- .../typeinference/typeAlgo/TYPEStmt.java | 10 ++++++++- src/test/java/TestComplete.java | 9 ++++++++ 14 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 src/main/java/de/dhbwstuttgart/syntaxtree/statement/Continue.java create mode 100644 src/main/java/de/dhbwstuttgart/target/tree/expression/TargetDo.java diff --git a/resources/bytecode/javFiles/While.jav b/resources/bytecode/javFiles/While.jav index df259cf5..cdd41f51 100644 --- a/resources/bytecode/javFiles/While.jav +++ b/resources/bytecode/javFiles/While.jav @@ -9,4 +9,13 @@ public class While { } return x; } + + public m2() { + int i = 0; + do { + ++i; + } while(i < 10); + + return i; + } } \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index b3c1fe20..8df566b9 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -978,6 +978,27 @@ public class Codegen { mv.visitLabel(end); break; } + case TargetDo _do: { + Label start = new Label(); + Label end = new Label(); + Label check = new Label(); + + var env = new BreakEnv(); + env.startLabel = check; + env.endLabel = end; + + mv.visitLabel(start); + state.breakStack.push(env); + generate(state, _do.body()); + state.breakStack.pop(); + + mv.visitLabel(check); + generate(state, _do.cond()); + mv.visitJumpInsn(IFEQ, end); + mv.visitJumpInsn(GOTO, start); + mv.visitLabel(end); + break; + } case TargetIf _if: { generate(state, _if.cond()); Label _else = new Label(); diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index abe38580..f4587b6b 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -597,8 +597,12 @@ public class StatementGenerator { } private Statement convert(Java17Parser.ContinuestmtContext stmt) { - // TODO - throw new NotImplementedException(); + Token offset = stmt.getStart(); + if (!Objects.isNull(stmt.identifier())) { + return new Continue(localVars.get(stmt.identifier().getText()), offset); + } else { + return new Continue(TypePlaceholder.fresh(offset), offset); + } } private Statement convert(Java17Parser.SemistmtContext stmt) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java index bc963fb3..2b4fff9f 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java @@ -236,6 +236,11 @@ public abstract class AbstractASTWalker implements ASTVisitor { aBreak.accept(this); } + @Override + public void visit(Continue aContinue) { + aContinue.accept(this); + } + @Override public void visit(StaticClassName staticClassName) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java b/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java index 1f1dc61c..78148964 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java @@ -53,6 +53,8 @@ public interface StatementVisitor { void visit(Break aBreak); + void visit(Continue aContinue); + void visit(Yield aYield); void visit(StaticClassName staticClassName); diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/statement/Continue.java b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/Continue.java new file mode 100644 index 00000000..7da44743 --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/Continue.java @@ -0,0 +1,18 @@ +package de.dhbwstuttgart.syntaxtree.statement; + +import de.dhbwstuttgart.syntaxtree.StatementVisitor; +import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class Continue extends Statement { + + public Continue(RefTypeOrTPHOrWildcardOrGeneric type, Token offset) { + super(type, offset); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + +} diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java b/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java index bb24aae3..7297dd87 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java @@ -333,6 +333,11 @@ public class OutputGenerator implements ASTVisitor { out.append("break"); } + @Override + public void visit(Continue aContinue) { + out.append("continue"); + } + @Override public void visit(StaticClassName staticClassName) { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 715ece94..7e50585a 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -261,6 +261,11 @@ public class StatementToTargetExpression implements ASTVisitor { result = new TargetBreak(); } + @Override + public void visit(Continue aContinue) { + result = new TargetContinue(); + } + @Override public void visit(StaticClassName staticClassName) { result = new TargetClassName(converter.convert(staticClassName.getType())); @@ -283,7 +288,7 @@ public class StatementToTargetExpression implements ASTVisitor { @Override public void visit(DoStmt whileStmt) { - throw new NotImplementedException(); + result = new TargetDo(converter.convert(whileStmt.expr), converter.convert(whileStmt.loopBlock)); } // TODO These two might not be necessary diff --git a/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java b/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java index 7b6f2a5f..d26cbbd9 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java @@ -124,6 +124,11 @@ public abstract class TracingStatementVisitor implements StatementVisitor { } + @Override + public void visit(Continue aContinue) { + + } + @Override public void visit(StaticClassName staticClassName) { diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetDo.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetDo.java new file mode 100644 index 00000000..7329b2ea --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetDo.java @@ -0,0 +1,4 @@ +package de.dhbwstuttgart.target.tree.expression; + +public record TargetDo(TargetExpression cond, TargetExpression body) implements TargetExpression { +} diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpression.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpression.java index e0bbc523..b82cfd79 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpression.java @@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree.expression; import de.dhbwstuttgart.target.tree.type.*; public sealed interface TargetExpression - permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetPattern, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetTernary, TargetThis, TargetThrow, TargetUnaryOp, TargetVarDecl, TargetWhile, TargetYield { + permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetDo, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetPattern, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetTernary, TargetThis, TargetThrow, TargetUnaryOp, TargetVarDecl, TargetWhile, TargetYield { default TargetType type() { return null; diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetWhile.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetWhile.java index e1a3690c..463702bd 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetWhile.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetWhile.java @@ -1,6 +1,4 @@ package de.dhbwstuttgart.target.tree.expression; -import de.dhbwstuttgart.target.tree.type.TargetType; - public record TargetWhile(TargetExpression cond, TargetExpression body) implements TargetExpression { } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java index be402d08..e068d9b2 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java @@ -514,6 +514,11 @@ public class TYPEStmt implements StatementVisitor { } + @Override + public void visit(Continue aContinue) { + + } + @Override public void visit(StaticClassName staticClassName) { // Hier entstehen keine Constraints @@ -569,7 +574,10 @@ public class TYPEStmt implements StatementVisitor { @Override public void visit(DoStmt whileStmt) { - throw new NotImplementedException(); + RefType booleanType = new RefType(ASTFactory.createClass(java.lang.Boolean.class).getClassName(), new NullToken()); + whileStmt.expr.accept(this); + constraintsSet.addUndConstraint(new Pair(whileStmt.expr.getType(), booleanType, PairOperator.EQUALSDOT, loc(whileStmt.expr.getOffset()))); + whileStmt.loopBlock.accept(this); } @Override diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index bc844bc0..6b685b92 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -925,6 +925,15 @@ public class TestComplete { assertEquals(clazz.getDeclaredMethod("main", Integer.class).invoke(instance, 5), "small"); } + @Test + public void testWhile() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "While.jav"); + var clazz = classFiles.get("While"); + var instance = clazz.getDeclaredConstructor().newInstance(); + assertEquals(clazz.getDeclaredMethod("m", Integer.class).invoke(instance, 5), 5); + assertEquals(clazz.getDeclaredMethod("m2").invoke(instance), 10); + } + @Test public void testBug122() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug122.jav"); From b824680508f87b77d8e0f5a11aeae6a6a68a226f Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Wed, 22 May 2024 12:55:47 +0200 Subject: [PATCH 02/12] Fix #335 --- .../java/de/dhbwstuttgart/environment/DirectoryClassLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java b/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java index f3d87641..0b69dead 100644 --- a/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java +++ b/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java @@ -24,7 +24,7 @@ public class DirectoryClassLoader extends URLClassLoader implements IByteArrayCl } private static URL dirToURL(File url){ - if(!url.isDirectory())throw new RuntimeException(url.toString() + " is not a directory"); + //if(!url.isDirectory())throw new RuntimeException(url.toString() + " is not a directory"); try { return url.toURI().toURL(); } catch (MalformedURLException e) { From 5b4ea5a0c50ae85f6b2bf2e94c512b2f36564b9c Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 22 May 2024 23:47:50 +0200 Subject: [PATCH 03/12] fix #327 and add support for glob syntax in classpath input --- .../environment/DirectoryClassLoader.java | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java b/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java index 0b69dead..8fba019a 100644 --- a/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java +++ b/src/main/java/de/dhbwstuttgart/environment/DirectoryClassLoader.java @@ -5,31 +5,61 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; +import java.nio.file.*; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class DirectoryClassLoader extends URLClassLoader implements IByteArrayClassLoader { - public DirectoryClassLoader(File directory, java.lang.ClassLoader parent) { - super(generateURLArray(dirToURL(directory)), parent); - } +// public DirectoryClassLoader(File directory, java.lang.ClassLoader parent) { +// super(generateURLArray(dirToURL(directory)), parent); +// } public DirectoryClassLoader(List directory, java.lang.ClassLoader parent) { - super(directory.stream().map(DirectoryClassLoader::dirToURL).collect(Collectors.toList()).toArray(new URL[0]), parent); + super(directory.stream().map(DirectoryClassLoader::dirToURL).flatMap(List::stream).collect(Collectors.toList()).toArray(new URL[0]), parent.getParent()); } private static URL[] generateURLArray(URL url) { return new URL[]{url}; } - private static URL dirToURL(File url){ + private static List dirToURL(File file) { //if(!url.isDirectory())throw new RuntimeException(url.toString() + " is not a directory"); - try { - return url.toURI().toURL(); - } catch (MalformedURLException e) { - throw new RuntimeException(e); + + Path dir; + if (file.isDirectory()) { + try { + return List.of(file.toURI().toURL()); // if file is a directory, use it as is + } catch (MalformedURLException e) { + e.printStackTrace(); + return List.of(); + } } + + dir = file.toPath().getParent(); // if file is not a directory, get its parent directory + String pattern = file.toPath().getFileName().toString(); // use the file name as a glob pattern + + List urls = new ArrayList<>(); + + try { + urls = Files.walk(dir) + .filter(Files::isRegularFile) // only consider files (not directories) + .filter(path -> { + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern); + return matcher.matches(path.getFileName()); // match the file name against the pattern + }) + .map(path -> { + try { + return path.toUri().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + }) // convert the path to a URL + .toList(); // print the path of each matching file + } catch (IOException | RuntimeException e) { + e.printStackTrace(); + } + return urls; } @Override From 141e1cbc94440c0b99f23d1162f54bd9e1f2f717 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Thu, 23 May 2024 11:39:56 +0200 Subject: [PATCH 04/12] Make wildcard imports work again #330 --- pom.xml | 12 ++-- .../bytecode/javFiles/ImportWildcard.jav | 5 ++ .../de/dhbwstuttgart/core/JavaTXCompiler.java | 2 +- .../environment/CompilationEnvironment.java | 12 +--- .../environment/PackageCrawler.java | 69 ++++++------------- .../SyntaxTreeGenerator.java | 4 -- .../TypeInferenceBlockInformation.java | 1 - src/test/java/TestComplete.java | 7 ++ 8 files changed, 43 insertions(+), 69 deletions(-) create mode 100644 resources/bytecode/javFiles/ImportWildcard.jav diff --git a/pom.xml b/pom.xml index f356ce82..120f4204 100644 --- a/pom.xml +++ b/pom.xml @@ -29,14 +29,14 @@ http://maven.apache.org/maven-v4_0_0.xsd"> 2.6 - com.google.guava - guava - 22.0 + io.github.classgraph + classgraph + 4.8.172 - org.reflections - reflections - 0.9.11 + com.google.guava + guava + 33.2.0-jre diff --git a/resources/bytecode/javFiles/ImportWildcard.jav b/resources/bytecode/javFiles/ImportWildcard.jav new file mode 100644 index 00000000..a64e9ae2 --- /dev/null +++ b/resources/bytecode/javFiles/ImportWildcard.jav @@ -0,0 +1,5 @@ +import java.lang.*; + +public class ImportWildcard { + m(a, b) { return a * b; } +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 068f1784..62d69b16 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -98,7 +98,7 @@ public class JavaTXCompiler { } if (outputPath != null) path.add(outputPath); classLoader = new DirectoryClassLoader(path, ClassLoader.getSystemClassLoader()); - environment = new CompilationEnvironment(sources); + environment = new CompilationEnvironment(sources, classLoader); classPath = path; this.outputPath = outputPath; diff --git a/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java b/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java index 4b802fe5..ad16e766 100644 --- a/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java +++ b/src/main/java/de/dhbwstuttgart/environment/CompilationEnvironment.java @@ -34,7 +34,7 @@ public class CompilationEnvironment { * * @param sourceFiles die zu kompilierenden Dateien */ - public CompilationEnvironment(List sourceFiles) { + public CompilationEnvironment(List sourceFiles, DirectoryClassLoader classLoader) { /** * Java 9 bringt einige Ă„nderungen am Classloader So funktioniert der BootClassLoader nicht mehr. hier gibts ein paar Quellen zum nachlesen: http://java9.wtf/class-loading/ https://stackoverflow.com/questions/46494112/classloaders-hierarchy-in-java-9 * @@ -54,7 +54,7 @@ public class CompilationEnvironment { // librarys = Arrays.asList(loader.getURLs()); this.sourceFiles = sourceFiles; - this.packageCrawler = new PackageCrawler(librarys); + this.packageCrawler = new PackageCrawler(classLoader); } public void addClassesToRegistry(JavaClassRegistry registry, SourceFileContext tree, File sourceFile, JavaTXCompiler compiler) throws ClassNotFoundException, IOException { @@ -104,12 +104,4 @@ public class CompilationEnvironment { return packageName; } - public List getAllAvailableClasses() { - List ret = new ArrayList<>(); - for (Class c : new PackageCrawler(librarys).getAllAvailableClasses()) { - ret.add(ASTFactory.createClass(c)); - } - return ret; - } - } diff --git a/src/main/java/de/dhbwstuttgart/environment/PackageCrawler.java b/src/main/java/de/dhbwstuttgart/environment/PackageCrawler.java index 646440b1..f645c3e9 100644 --- a/src/main/java/de/dhbwstuttgart/environment/PackageCrawler.java +++ b/src/main/java/de/dhbwstuttgart/environment/PackageCrawler.java @@ -1,17 +1,10 @@ package de.dhbwstuttgart.environment; -import java.net.URL; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ScanResult; + import java.util.*; -import org.reflections.Reflections; -import org.reflections.scanners.ResourcesScanner; -import org.reflections.scanners.SubTypesScanner; -import org.reflections.util.ConfigurationBuilder; -import org.reflections.util.FilterBuilder; - -import de.dhbwstuttgart.parser.scope.JavaClassName; -import org.reflections.vfs.SystemDir; - /** * Hilft beim Durchsuchen von Packages * Benutzt die Reflections-Library (https://github.com/ronmamo/reflections) @@ -19,48 +12,30 @@ import org.reflections.vfs.SystemDir; */ public class PackageCrawler { - final URL[] urls; - public PackageCrawler(List urlList) { - urls = urlList.toArray(new URL[0]); + final DirectoryClassLoader classLoader; + public PackageCrawler(DirectoryClassLoader classLoader) { + this.classLoader = classLoader; } - public Set> getClassesInPackage(String packageName){ - /* - List classLoadersList = new LinkedList(); - classLoadersList.add(Thread.currentThread().getContextClassLoader()); - classLoadersList.add(ClasspathHelper.staticClassLoader()); - classLoadersList.add(Thread.currentThread().getContextClassLoader().getParent()); - classLoadersList.add(DirectoryClassLoader.getSystemClassLoader()); - String bootClassPath = System.getProperty("sun.boot.class.path"); - ArrayList urlList = new ArrayList<>(); - for(String path : bootClassPath.split(";")) { - try { - urlList.add(new URL("file:"+path)); - } catch (MalformedURLException e) { - new DebugException("Fehler im Classpath auf diesem System"); - } - } - URL[] urls = urlList.toArray(new URL[0]); - classLoadersList.add(new URLClassLoader(urls, DirectoryClassLoader.getSystemClassLoader())); - */ - Reflections reflections = new Reflections(new ConfigurationBuilder() - .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner()) - .setUrls(urls) - .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(packageName)))); + public Set> getClassesInPackage(String packageName) { + var res = new HashSet>(); - Set> classes = reflections.getSubTypesOf(Object.class); + try (ScanResult result = new ClassGraph() + .enableClassInfo() + .enableSystemJarsAndModules() + .addClassLoader(classLoader) + .acceptPackages(packageName) + .scan()) { - return classes; - } + for (var info : result.getAllClasses()) { + try { + var clazz = Class.forName(info.getName()); + res.add(clazz); + } catch (ClassNotFoundException ignored) {} + } + }; - public Set> getAllAvailableClasses(){ - Reflections reflections = new Reflections(new ConfigurationBuilder() - .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner()) - .setUrls(urls)); - - Set> classes = reflections.getSubTypesOf(Object.class); - - return classes; + return res; } public Map getClassNames(String packageName){ diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index 003f2580..de36c9f0 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -71,10 +71,6 @@ import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.Void; -import de.dhbwstuttgart.typeinference.constraints.GenericsResolver; -import javassist.compiler.SyntaxError; - -import javax.swing.text.html.Option; public class SyntaxTreeGenerator { private JavaClassRegistry reg; diff --git a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/TypeInferenceBlockInformation.java b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/TypeInferenceBlockInformation.java index 6b9f54a5..7fe843d1 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/TypeInferenceBlockInformation.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/TypeInferenceBlockInformation.java @@ -35,7 +35,6 @@ public class TypeInferenceBlockInformation extends TypeInferenceInformation { public ClassOrInterface getSuperClass() { for (var clazz : getAvailableClasses()) { - System.out.println(currentClass.getSuperClass().getName()); if (clazz.getClassName().equals(currentClass.getSuperClass().getName())) return clazz; } diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 6b685b92..87c6f2aa 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -934,6 +934,13 @@ public class TestComplete { assertEquals(clazz.getDeclaredMethod("m2").invoke(instance), 10); } + @Test + public void testImportWildcard() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "ImportWildcard.jav"); + var clazz = classFiles.get("ImportWildcard"); + var instance = clazz.getDeclaredConstructor().newInstance(); + } + @Test public void testBug122() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug122.jav"); From 12bb613eb0080e57af06f909160ddc89c786ebc4 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Fri, 24 May 2024 12:46:26 +0200 Subject: [PATCH 05/12] Fix test cases --- src/test/java/targetast/ASTToTypedTargetAST.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/targetast/ASTToTypedTargetAST.java b/src/test/java/targetast/ASTToTypedTargetAST.java index a4fa2ff0..3c4c7fed 100644 --- a/src/test/java/targetast/ASTToTypedTargetAST.java +++ b/src/test/java/targetast/ASTToTypedTargetAST.java @@ -57,7 +57,7 @@ public class ASTToTypedTargetAST { var file = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Tph2.jav").toFile(); var compiler = new JavaTXCompiler(file); var resultSet = compiler.typeInference(file); - var converter = new ASTToTargetAST(resultSet); + var converter = new ASTToTargetAST(compiler, resultSet); var classes = compiler.sourceFiles.get(file).getClasses(); var tphAndGenerics = TestCodegen.generateClass(converter.convert(classes.get(0)), new ByteArrayClassLoader()); @@ -68,7 +68,7 @@ public class ASTToTypedTargetAST { var file = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Cycle.jav").toFile(); var compiler = new JavaTXCompiler(file); var resultSet = compiler.typeInference(file); - var converter = new ASTToTargetAST(resultSet); + var converter = new ASTToTargetAST(compiler, resultSet); var classes = compiler.sourceFiles.get(file).getClasses(); var cycle = TestCodegen.generateClass(converter.convert(classes.get(0)), new ByteArrayClassLoader()); @@ -79,7 +79,7 @@ public class ASTToTypedTargetAST { var file = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Infimum.jav").toFile(); var compiler = new JavaTXCompiler(file); var resultSet = compiler.typeInference(file); - var converter = new ASTToTargetAST(resultSet); + var converter = new ASTToTargetAST(compiler, resultSet); var classes = compiler.sourceFiles.get(file).getClasses(); var infimum = TestCodegen.generateClass(converter.convert(classes.get(0)), new ByteArrayClassLoader()); @@ -90,7 +90,7 @@ public class ASTToTypedTargetAST { var file = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Gen.jav").toFile(); var compiler = new JavaTXCompiler(file); var resultSet = compiler.typeInference(file); - var converter = new ASTToTargetAST(resultSet); + var converter = new ASTToTargetAST(compiler, resultSet); var classes = compiler.sourceFiles.get(file).getClasses(); var generics = TestCodegen.generateClass(converter.convert(classes.get(0)), new ByteArrayClassLoader()); @@ -124,7 +124,7 @@ public class ASTToTypedTargetAST { var file = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Generics2.jav").toFile(); var compiler = new JavaTXCompiler(file); var resultSet = compiler.typeInference(file); - var converter = new ASTToTargetAST(resultSet); + var converter = new ASTToTargetAST(compiler, resultSet); var classes = compiler.sourceFiles.get(file).getClasses(); var generics2 = TestCodegen.generateClass(converter.convert(classes.get(0)), new ByteArrayClassLoader()); @@ -140,7 +140,7 @@ public class ASTToTypedTargetAST { var file = Path.of(System.getProperty("user.dir"), "/resources/bytecode/javFiles/Generics3.jav").toFile(); var compiler = new JavaTXCompiler(file); var resultSet = compiler.typeInference(file); - var converter = new ASTToTargetAST(resultSet); + var converter = new ASTToTargetAST(compiler, resultSet); var classes = compiler.sourceFiles.get(file).getClasses(); var generics3 = TestCodegen.generateClass(converter.convert(classes.get(0)), new ByteArrayClassLoader()); From 99f219de3b40d8e94024984f0e63ef396d7396d9 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Mon, 27 May 2024 12:14:00 +0200 Subject: [PATCH 06/12] Work on #338, partially fixed --- resources/bytecode/javFiles/Bug338.jav | 11 +++++++++++ .../dhbwstuttgart/target/generate/ASTToTargetAST.java | 8 +++++--- src/test/java/TestComplete.java | 7 +++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 resources/bytecode/javFiles/Bug338.jav diff --git a/resources/bytecode/javFiles/Bug338.jav b/resources/bytecode/javFiles/Bug338.jav new file mode 100644 index 00000000..fa846e95 --- /dev/null +++ b/resources/bytecode/javFiles/Bug338.jav @@ -0,0 +1,11 @@ +import java.util.List; +import java.lang.Integer; +import java.lang.String; +import java.lang.Object; +import java.util.List; + +public class Bug338 { + public hashCode() { + return List.of(42); + } +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 1c485d7e..e62fbf80 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -366,7 +366,6 @@ public class ASTToTargetAST { for (var i = 0; i < params.size(); i++) { var a = TargetType.toPrimitive(params.get(i).pattern().type()); var b = convert(sParams.getFormalparalist().get(i).getType()); - System.out.println(a + " " + b); if (!Objects.equals(a, b)) return false; } return true; @@ -387,8 +386,11 @@ public class ASTToTargetAST { var superMethod = findSuperMethodToOverride(currentClass, method.getName(), params); if (superMethod.isPresent()) { // If we find a super method to override, use its parameters and return types - returnType = convert(superMethod.get().getReturnType(), this.generics.javaGenerics); - params = convert(superMethod.get().getParameterList(), method.getParameterList(), this.generics.javaGenerics); + var newReturnType = convert(superMethod.get().getReturnType(), this.generics.javaGenerics); + if (newReturnType instanceof TargetPrimitiveType && TargetType.toPrimitive(returnType).equals(newReturnType)) { + returnType = newReturnType; + params = convert(superMethod.get().getParameterList(), method.getParameterList(), this.generics.javaGenerics); + } } List finalParams = params; diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 93cfb387..3058ac14 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -1084,4 +1084,11 @@ public class TestComplete { var res = clazz.getDeclaredMethod("convert", List.class).invoke(instance, list); assertEquals(res, List.of(6, 7, 8)); } + + @Test + public void testBug338() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug338.jav"); + var clazz = classFiles.get("Bug338"); + var instance = clazz.getDeclaredConstructor().newInstance(); + } } From 4880527d4d5ac17a7383643684fa22651fce3122 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Mon, 27 May 2024 15:51:48 +0200 Subject: [PATCH 07/12] Give an exception if a method has been duplicated --- .../target/generate/ASTToTargetAST.java | 31 +++++++++++++------ .../target/tree/TargetMethod.java | 12 +++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index e62fbf80..bddeeca7 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -1,5 +1,6 @@ package de.dhbwstuttgart.target.generate; +import de.dhbwstuttgart.bytecode.CodeGenException; import de.dhbwstuttgart.bytecode.FunNGenerator; import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.environment.ByteArrayClassLoader; @@ -160,11 +161,11 @@ public class ASTToTargetAST { var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList(); var fields = input.getFieldDecl().stream().map(this::convert).toList(); - var methods = groupOverloads(input.getMethods()).stream().map(m -> convert(input, m)).flatMap(List::stream).toList(); + var methods = groupOverloads(input.getMethods()).stream().map(m -> convert(input, m)).flatMap(Set::stream).toList(); TargetMethod staticConstructor = null; if (input.getStaticInitializer().isPresent()) - staticConstructor = this.convert(input, input.getStaticInitializer().get()).get(0); + staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow(); if (input instanceof Record) return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); @@ -289,11 +290,11 @@ public class ASTToTargetAST { return res.toString(); } - private List convert(ClassOrInterface clazz, List overloadedMethods) { + private Set convert(ClassOrInterface clazz, List overloadedMethods) { if (overloadedMethods.size() == 1) { - return convert(clazz, overloadedMethods.get(0)); + return convert(clazz, overloadedMethods.getFirst()); } - var res = new ArrayList(); + var methods = new ArrayList(); for (var method : overloadedMethods) { var newMethod = new Method( method.modifier, @@ -305,7 +306,7 @@ public class ASTToTargetAST { method.getGenerics(), method.getOffset() ); - res.add(newMethod); + methods.add(newMethod); } // TODO Record overloading @@ -328,7 +329,15 @@ public class ASTToTargetAST { var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken()); res.add(entryPoint); // TODO*/ - return res.stream().map(m -> convert(clazz, m)).flatMap(List::stream).toList(); + var res = new HashSet(); + for (var method : methods) { + var overloads = convert(clazz, method); + for (var overload : overloads) { + if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature()); + res.add(overload); + } + } + return res; } private Expression makeRecordSwitch(RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList params, List overloadedMethods) { @@ -372,9 +381,9 @@ public class ASTToTargetAST { }).findFirst(); } - private List convert(ClassOrInterface currentClass, Method method) { + private Set convert(ClassOrInterface currentClass, Method method) { generics = all.get(0); - List result = new ArrayList<>(); + Set result = new HashSet<>(); Set> parameterSet = new HashSet<>(); for (var s : all) { @@ -402,10 +411,12 @@ public class ASTToTargetAST { var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); - result.add(new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature)); + var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature); + result.add(newMethod); parameterSet.add(params); } } + return result; } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/TargetMethod.java b/src/main/java/de/dhbwstuttgart/target/tree/TargetMethod.java index 5a8b9368..bdabc81e 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/TargetMethod.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/TargetMethod.java @@ -6,6 +6,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType; import org.objectweb.asm.Opcodes; import java.util.List; +import java.util.Objects; import java.util.Set; public record TargetMethod(int access, String name, TargetBlock block, Signature signature, Signature txSignature) { @@ -64,5 +65,16 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature public boolean isStatic() { return (access & Opcodes.ACC_STATIC) != 0; } + + @Override + public boolean equals(Object other) { + if (!(other instanceof TargetMethod otherMethod)) return false; + return otherMethod.signature.equals(this.signature) && otherMethod.name.equals(this.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, signature); + } } From 7650813bb72f5a0f197d9ec23d2e82d083bb4827 Mon Sep 17 00:00:00 2001 From: Ruben Date: Thu, 6 Jun 2024 12:06:28 +0200 Subject: [PATCH 08/12] feat: changes in Grammar and Parser so typeless Recs get recognised --- resources/bytecode/javFiles/SwitchInfered.jav | 17 +++++++++++++++++ .../dhbwstuttgart/parser/antlr/Java17Parser.g4 | 6 ++++-- .../SyntaxTreeGenerator/StatementGenerator.java | 2 +- src/test/java/TestComplete.java | 9 +++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 resources/bytecode/javFiles/SwitchInfered.jav diff --git a/resources/bytecode/javFiles/SwitchInfered.jav b/resources/bytecode/javFiles/SwitchInfered.jav new file mode 100644 index 00000000..d11c760d --- /dev/null +++ b/resources/bytecode/javFiles/SwitchInfered.jav @@ -0,0 +1,17 @@ +import java.lang.Integer; +import java.lang.Object; +import java.lang.Float; + +public record Rec(Integer a, Object b) {} + +public class SwitchInfered { + public main(o) { + return switch (o) { + case Rec(a, b) -> a + b; + case Rec(Integer a, Float b) -> a + 10; + case Rec(Integer a, Rec(Integer b, Integer c)) -> a + b + c; + case Integer i -> i; + default -> 0; + }; + } +} \ No newline at end of file diff --git a/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 b/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 index be87c4d7..891c47b3 100644 --- a/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 +++ b/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 @@ -658,10 +658,12 @@ primaryPattern recordPattern : typeType recordStructurePattern identifier? + //| recordStructurePattern identifier? ; typePattern : variableModifier* typeType identifier + | variableModifier* identifier ; recordStructurePattern @@ -717,10 +719,10 @@ switchLabeledRule ; switchLabelCase - : CASE expressionList (ARROW | COLON) #labeledRuleExprList - | CASE NULL_LITERAL (ARROW | COLON) #labeledRuleNull + : CASE NULL_LITERAL (ARROW | COLON) #labeledRuleNull | CASE pattern (ARROW | COLON) #labeledRulePattern | DEFAULT (ARROW | COLON) #labeledRuleDefault + | CASE expressionList (ARROW | COLON) #labeledRuleExprList ; // Java20 diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index f4587b6b..11716318 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -457,7 +457,7 @@ public class StatementGenerator { case TPatternContext tPattern: TypePatternContext typePattern = tPattern.typePattern(); var text = typePattern.identifier().getText(); - var type = TypeGenerator.convert(typePattern.typeType(), reg, generics); + var type = typePattern.typeType() == null ? TypePlaceholder.fresh(typePattern.getStart()) : TypeGenerator.convert(typePattern.typeType(), reg, generics); localVars.put(text, type); return new FormalParameter(text, type, typePattern.getStart()); case RPatternContext rPattern: diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index fd4b8b5e..9d318ba6 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -673,6 +673,15 @@ public class TestComplete { assertEquals(swtch.invoke(instance, "Some string"), 0); } + @Ignore("Not implemented") + @Test + public void testSwitchInfered() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchInfered.jav"); + var clazz = classFiles.get("SwitchInfered"); + var instance = clazz.getDeclaredConstructor().newInstance(); + var swtch = clazz.getDeclaredMethod("main", Object.class); + } + @Ignore("Not implemented") @Test public void testSwitch2() throws Exception { From ea217d16d5a1d635ac7fe961b98c2ad993c14ac5 Mon Sep 17 00:00:00 2001 From: Ruben Date: Thu, 6 Jun 2024 12:07:32 +0200 Subject: [PATCH 09/12] Revert "feat: changes in Grammar and Parser so typeless Recs get recognised" This reverts commit 7650813bb72f5a0f197d9ec23d2e82d083bb4827. --- resources/bytecode/javFiles/SwitchInfered.jav | 17 ----------------- .../dhbwstuttgart/parser/antlr/Java17Parser.g4 | 6 ++---- .../SyntaxTreeGenerator/StatementGenerator.java | 2 +- src/test/java/TestComplete.java | 9 --------- 4 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 resources/bytecode/javFiles/SwitchInfered.jav diff --git a/resources/bytecode/javFiles/SwitchInfered.jav b/resources/bytecode/javFiles/SwitchInfered.jav deleted file mode 100644 index d11c760d..00000000 --- a/resources/bytecode/javFiles/SwitchInfered.jav +++ /dev/null @@ -1,17 +0,0 @@ -import java.lang.Integer; -import java.lang.Object; -import java.lang.Float; - -public record Rec(Integer a, Object b) {} - -public class SwitchInfered { - public main(o) { - return switch (o) { - case Rec(a, b) -> a + b; - case Rec(Integer a, Float b) -> a + 10; - case Rec(Integer a, Rec(Integer b, Integer c)) -> a + b + c; - case Integer i -> i; - default -> 0; - }; - } -} \ No newline at end of file diff --git a/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 b/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 index 891c47b3..be87c4d7 100644 --- a/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 +++ b/src/main/antlr4/de/dhbwstuttgart/parser/antlr/Java17Parser.g4 @@ -658,12 +658,10 @@ primaryPattern recordPattern : typeType recordStructurePattern identifier? - //| recordStructurePattern identifier? ; typePattern : variableModifier* typeType identifier - | variableModifier* identifier ; recordStructurePattern @@ -719,10 +717,10 @@ switchLabeledRule ; switchLabelCase - : CASE NULL_LITERAL (ARROW | COLON) #labeledRuleNull + : CASE expressionList (ARROW | COLON) #labeledRuleExprList + | CASE NULL_LITERAL (ARROW | COLON) #labeledRuleNull | CASE pattern (ARROW | COLON) #labeledRulePattern | DEFAULT (ARROW | COLON) #labeledRuleDefault - | CASE expressionList (ARROW | COLON) #labeledRuleExprList ; // Java20 diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index 11716318..f4587b6b 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -457,7 +457,7 @@ public class StatementGenerator { case TPatternContext tPattern: TypePatternContext typePattern = tPattern.typePattern(); var text = typePattern.identifier().getText(); - var type = typePattern.typeType() == null ? TypePlaceholder.fresh(typePattern.getStart()) : TypeGenerator.convert(typePattern.typeType(), reg, generics); + var type = TypeGenerator.convert(typePattern.typeType(), reg, generics); localVars.put(text, type); return new FormalParameter(text, type, typePattern.getStart()); case RPatternContext rPattern: diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 9d318ba6..fd4b8b5e 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -673,15 +673,6 @@ public class TestComplete { assertEquals(swtch.invoke(instance, "Some string"), 0); } - @Ignore("Not implemented") - @Test - public void testSwitchInfered() throws Exception { - var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchInfered.jav"); - var clazz = classFiles.get("SwitchInfered"); - var instance = clazz.getDeclaredConstructor().newInstance(); - var swtch = clazz.getDeclaredMethod("main", Object.class); - } - @Ignore("Not implemented") @Test public void testSwitch2() throws Exception { From 7e6aeaf728d521c27c40b14e2800202f817170ff Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Fri, 7 Jun 2024 12:03:16 +0200 Subject: [PATCH 10/12] Make Function Types implement others to allow Subtyping, fixes #337 --- pom.xml | 4 +- resources/bytecode/javFiles/Bug337.jav | 10 ++++ .../dhbwstuttgart/bytecode/FunNGenerator.java | 42 ++++++++++--- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 1 + .../target/generate/ASTToTargetAST.java | 60 +++++++++++++++---- src/test/java/TestComplete.java | 8 +++ src/test/java/targetast/TestCodegen.java | 4 ++ 7 files changed, 110 insertions(+), 19 deletions(-) create mode 100644 resources/bytecode/javFiles/Bug337.jav diff --git a/pom.xml b/pom.xml index 120f4204..d9dbc114 100644 --- a/pom.xml +++ b/pom.xml @@ -54,8 +54,8 @@ http://maven.apache.org/maven-v4_0_0.xsd"> 3.11.0 --enable-preview - 21 - 21 + 22 + 22 diff --git a/resources/bytecode/javFiles/Bug337.jav b/resources/bytecode/javFiles/Bug337.jav new file mode 100644 index 00000000..92bb6fa8 --- /dev/null +++ b/resources/bytecode/javFiles/Bug337.jav @@ -0,0 +1,10 @@ +import java.lang.Integer; +import java.lang.Number; +import java.lang.Object; + +public class Bug337 { + public void main() { + Fun1$$ fun1 = x -> x.hashCode() + 1; + Fun1$$ fun2 = fun1; + } +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java index 411d9bf2..819f5a3e 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java @@ -33,6 +33,23 @@ public class FunNGenerator { public static class GenericParameters { int start; public List parameters = new ArrayList<>(); + final String descriptor; + final List inParams; + + public GenericParameters(List params) { + this.inParams = params; + var type = new TargetRefType(FunNGenerator.getSuperClassName(params.size() - 1), params); + descriptor = applyDescriptor(type, this); + System.out.println(this.parameters); + } + + public TargetType getReturnType() { + return FunNGenerator.getReturnType(inParams); + } + + public List getArguments() { + return FunNGenerator.getArguments(inParams); + } } private static String applyDescriptor(TargetType type, GenericParameters gep) { @@ -98,12 +115,11 @@ public class FunNGenerator { return String.format("Fun%d$$", numberArguments); } - public static byte[] generateSpecializedBytecode(List argumentTypes, TargetType returnType, GenericParameters gep) { - List parameters = Stream - .concat(argumentTypes.stream(), Stream.of(returnType)) - .toList(); + public static byte[] generateSpecializedBytecode(GenericParameters gep, List superInterfaces) { + var argumentTypes = gep.getArguments(); + var returnType = gep.getReturnType(); - StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters), gep)); + StringBuilder funNClassSignature = new StringBuilder(objectSignature + gep.descriptor); boolean containsGeneric = false; String genericSignature = "<"; @@ -114,10 +130,18 @@ public class FunNGenerator { genericSignature += ">"; if (containsGeneric) funNClassSignature.insert(0, genericSignature); - System.out.println(funNClassSignature.toString()); + + for (var superInterface : superInterfaces) { + funNClassSignature.append('L'); + funNClassSignature.append(superInterface); + funNClassSignature.append(';'); + } + + var interfaces = new ArrayList<>(superInterfaces); + interfaces.add(getSuperClassName(argumentTypes.size())); ClassWriter classWriter = new ClassWriter(0); - classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, new String[]{getSuperClassName(argumentTypes.size())}); + classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, interfaces.toArray(String[]::new)); classWriter.visitEnd(); return classWriter.toByteArray(); } @@ -133,6 +157,10 @@ public class FunNGenerator { } } + public static String getSpecializedClassName(GenericParameters gep) { + return getSpecializedClassName(getArguments(gep.inParams), getReturnType(gep.inParams)); + } + public static String getSpecializedClassName(List argumentTypes, TargetType returnType) { return String.format("Fun%d$$%s%s", argumentTypes.size(), diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index 62d69b16..ed11515c 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -783,6 +783,7 @@ public class JavaTXCompiler { }); } generatedGenerics.put(sf, converter.javaGenerics()); + converter.generateFunNTypes(); return generatedClasses; } diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 1c485d7e..3908af06 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -479,6 +479,55 @@ public class ASTToTargetAST { return TargetFunNType.fromParams(params, filteredParams); } + private boolean isSubtype(TargetType test, TargetType other) { + var testClass = compiler.getClass(new JavaClassName(test.name())); + var otherClass = compiler.getClass(new JavaClassName(other.name())); + if (testClass == null) return false; + while (testClass != null) { + if (testClass.equals(otherClass)) return true; + if (testClass.getClassName().equals(new JavaClassName("java.lang.Object"))) break; + testClass = compiler.getClass(testClass.getSuperClass().getName()); + } + return false; + } + + private boolean isSupertype(TargetType test, TargetType other) { + return isSubtype(other, test); + } + + private boolean isSubtype(FunNGenerator.GenericParameters test, FunNGenerator.GenericParameters other) { + if (test.getArguments().size() != other.getArguments().size()) return false; + if (!isSubtype(test.getReturnType(), other.getReturnType())) return false; + for (int i = 0; i < test.getArguments().size(); i++) { + var arg1 = test.getArguments().get(i); + var arg2 = other.getArguments().get(i); + if (!isSupertype(arg1, arg2)) return false; + } + return true; + } + + public void generateFunNTypes() { + for (var entry : usedFunN.entrySet()) { + var gep = entry.getValue(); + var superInterfaces = usedFunN.values().stream() + .filter(g -> !g.equals(gep)) + .filter(genericParameters -> isSubtype(gep, genericParameters)) + .map(FunNGenerator::getSpecializedClassName) + .toList(); + + var code = FunNGenerator.generateSpecializedBytecode(gep, superInterfaces); + + try { + classLoader.findClass(entry.getKey()); + } catch (ClassNotFoundException e) { + try { + classLoader.loadClass(code); + } catch (LinkageError ignored) {} + } + auxiliaries.put(entry.getKey(), code); + } + } + protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) { return input.acceptTV(new TypeVisitor<>() { @Override @@ -513,17 +562,8 @@ public class ASTToTargetAST { } FunNGenerator.GenericParameters gep = null; if (!usedFunN.containsKey(className)) { - gep = new FunNGenerator.GenericParameters(); - var code = FunNGenerator.generateSpecializedBytecode(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params), gep); - try { - classLoader.findClass(className); - } catch (ClassNotFoundException e) { - try { - classLoader.loadClass(code); - } catch (LinkageError ignored) {} - } + gep = new FunNGenerator.GenericParameters(params); usedFunN.put(className, gep); - auxiliaries.put(className, code); } else { gep = usedFunN.get(className); } diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 87c6f2aa..2b95681e 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -1131,4 +1131,12 @@ public class TestComplete { var clazz = classFiles.get("Bug333"); var instance = clazz.getDeclaredConstructor().newInstance(); } + + @Test + public void testBug337() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug337.jav"); + var clazz = classFiles.get("Bug337"); + var instance = clazz.getDeclaredConstructor().newInstance(); + clazz.getDeclaredMethod("main").invoke(instance); + } } diff --git a/src/test/java/targetast/TestCodegen.java b/src/test/java/targetast/TestCodegen.java index 3d698169..fb901776 100644 --- a/src/test/java/targetast/TestCodegen.java +++ b/src/test/java/targetast/TestCodegen.java @@ -60,6 +60,8 @@ public class TestCodegen { } }).collect(Collectors.toMap(Class::getName, Function.identity()))); + converter.generateFunNTypes(); + for (var entry : converter.auxiliaries.entrySet()) { writeClassFile(entry.getKey(), entry.getValue()); } @@ -104,6 +106,8 @@ public class TestCodegen { } }).collect(Collectors.toMap(Class::getName, Function.identity())); + converter.generateFunNTypes(); + for (var entry : converter.auxiliaries.entrySet()) { writeClassFile(entry.getKey(), entry.getValue()); } From 091a6b8f1f192b2270eb2088ee69f4e1d11d462c Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Fri, 7 Jun 2024 12:16:03 +0200 Subject: [PATCH 11/12] Fix merge conflict --- src/test/java/TestComplete.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 4076fede..7ca70857 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -1134,17 +1134,17 @@ public class TestComplete { } @Test -<<<<<<< HEAD public void testBug337() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug337.jav"); var clazz = classFiles.get("Bug337"); var instance = clazz.getDeclaredConstructor().newInstance(); clazz.getDeclaredMethod("main").invoke(instance); -======= + } + + @Test public void testBug338() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug338.jav"); var clazz = classFiles.get("Bug338"); var instance = clazz.getDeclaredConstructor().newInstance(); ->>>>>>> ea217d16d5a1d635ac7fe961b98c2ad993c14ac5 } } From ec92b5d5e137a7e30c46088a9cdf38bd5df4dc25 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Thu, 13 Jun 2024 17:23:19 +0200 Subject: [PATCH 12/12] Work on Bug #332 --- resources/bytecode/javFiles/Bug332.jav | 15 ++ .../target/generate/ASTToTargetAST.java | 144 +++++++++--------- .../generate/StatementToTargetExpression.java | 5 + src/test/java/TestComplete.java | 7 + 4 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 resources/bytecode/javFiles/Bug332.jav diff --git a/resources/bytecode/javFiles/Bug332.jav b/resources/bytecode/javFiles/Bug332.jav new file mode 100644 index 00000000..240dba0c --- /dev/null +++ b/resources/bytecode/javFiles/Bug332.jav @@ -0,0 +1,15 @@ +import java.lang.Object; + +interface Visitor { + public void visit(Object obj); + public void visit(ClassA a); +} + +class ClassA { + void accept(Visitor v) { + v.visit(this); + } +} + +public class Bug332 { +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 3280f295..d6e73ba7 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -5,7 +5,6 @@ import de.dhbwstuttgart.bytecode.FunNGenerator; import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.environment.ByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader; -import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.*; @@ -18,23 +17,25 @@ import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.typeinference.result.*; -import javax.sql.rowset.RowSetWarning; -import java.lang.annotation.Target; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.stream.StreamSupport; /** * @author dholle */ public class ASTToTargetAST { + record SignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {}; + record SignaturePairTarget(TargetType signature, TargetType parameter) {} + public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change protected List all; public Generics generics; final Map> userDefinedGenerics = new HashMap<>(); + final Map> tphsInMethods = new HashMap<>(); + private Method currentMethod; public final JavaTXCompiler compiler; @@ -78,6 +79,12 @@ public class ASTToTargetAST { this.generics = all.get(0); } + public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) { + var set = tphsInMethods.getOrDefault(currentMethod, new HashSet<>()); + set.add(new SignaturePair(signature, parameter)); + tphsInMethods.put(currentMethod, set); + } + Optional findMethod(ClassOrInterface owner, String name, List argumentList) { Optional method = Optional.empty(); while (method.isEmpty()) { @@ -131,6 +138,40 @@ public class ASTToTargetAST { return ret; } + public List> groupOverloads(ClassOrInterface input, List methods) { + var res = new ArrayList>(); + for (var method : methods) { + // Convert all methods + var methodsWithTphs = convert(input, method); + // Then check for methods with the same signature + var mapOfSignatures = new HashMap>(); + for (var m : methodsWithTphs) { + var methodsWithSameSignature = mapOfSignatures.getOrDefault(m.method.signature(), new ArrayList<>()); + methodsWithSameSignature.add(m); + mapOfSignatures.put(m.method.signature(), methodsWithSameSignature); + } + + var resMethods = new HashSet(); + for (var methodsWithSignature : mapOfSignatures.values()) { + outer: for (var m1 : methodsWithSignature) { + for (var m2 : methodsWithSignature) { + for (var i = 0; i < m1.args.size(); i++) { + var arg1 = m1.args.get(i); + var arg2 = m2.args.get(i); + if (arg1.parameter.equals(arg2.parameter)) { + if (isSupertype(arg1.signature, arg2.signature) && + !arg1.signature.equals(arg2.signature)) continue outer; + } + } + } + resMethods.add(m1.method); + } + } + res.add(resMethods.stream().toList()); + } + return res; + } + public TargetStructure convert(ClassOrInterface input) { Set javaGenerics = new HashSet<>(); Set txGenerics = new HashSet<>(); @@ -161,11 +202,11 @@ public class ASTToTargetAST { var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList(); var fields = input.getFieldDecl().stream().map(this::convert).toList(); - var methods = groupOverloads(input.getMethods()).stream().map(m -> convert(input, m)).flatMap(Set::stream).toList(); + var methods = groupOverloads(input, input.getMethods()).stream().flatMap(List::stream).toList(); TargetMethod staticConstructor = null; if (input.getStaticInitializer().isPresent()) - staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow(); + staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow().method; if (input instanceof Record) return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); @@ -206,6 +247,7 @@ public class ASTToTargetAST { generics = all.get(0); List result = new ArrayList<>(); Set> parameterSet = new HashSet<>(); + this.currentMethod = input; for (var s : all) { generics = s; @@ -225,56 +267,6 @@ public class ASTToTargetAST { return result; } - /** - * This only considers type patterns, all other methods aren't grouped together - * @param a - * @param b - * @return - */ - private boolean signatureEquals(Method a, Method b) { - if (!a.name.equals(b.name)) return false; - var para = a.getParameterList().getFormalparalist(); - var parb = b.getParameterList().getFormalparalist(); - if (para.size() != parb.size()) return false; - - for (var i = 0; i < para.size(); i++) { - var pa = para.get(i); - var pb = parb.get(i); - - if (pa instanceof RecordPattern rpa) { - if (pb instanceof RecordPattern rpb) { - if (rpa.getType().equals(rpb.getType())) continue; - } - return false; - } else if (pa.getType().equals(pb.getType())) { - continue; - } - return false; - } - - return true; - } - - // TODO Nested patterns - private List> groupOverloads(List input) { - var done = new HashSet(); - var res = new ArrayList>(); - for (var method : input) { - if (done.contains(method)) continue; - var overloads = new ArrayList(); - overloads.add(method); - done.add(method); - for (var method2 : input) { - if (!done.contains(method2) && signatureEquals(method, method2)) { - done.add(method2); - overloads.add(method2); - } - } - res.add(overloads); - } - return res; - } - private String encodeName(String name, ParameterList params) { var res = new StringBuilder(); res.append(name); @@ -290,9 +282,9 @@ public class ASTToTargetAST { return res.toString(); } - private Set convert(ClassOrInterface clazz, List overloadedMethods) { + private List convert(ClassOrInterface clazz, List overloadedMethods) { if (overloadedMethods.size() == 1) { - return convert(clazz, overloadedMethods.getFirst()); + return convert(clazz, overloadedMethods.getFirst()).stream().map(m -> m.method()).toList(); } var methods = new ArrayList(); for (var method : overloadedMethods) { @@ -329,10 +321,11 @@ public class ASTToTargetAST { var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken()); res.add(entryPoint); // TODO*/ - var res = new HashSet(); + var res = new ArrayList(); for (var method : methods) { var overloads = convert(clazz, method); - for (var overload : overloads) { + for (var m : overloads) { + var overload = m.method; if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature()); res.add(overload); } @@ -381,10 +374,12 @@ public class ASTToTargetAST { }).findFirst(); } - private Set convert(ClassOrInterface currentClass, Method method) { - generics = all.get(0); - Set result = new HashSet<>(); - Set> parameterSet = new HashSet<>(); + record MethodWithTphs(TargetMethod method, List args) {} + + private List convert(ClassOrInterface currentClass, Method method) { + generics = all.getFirst(); + List result = new ArrayList<>(); + this.currentMethod = method; for (var s : all) { generics = s; @@ -402,19 +397,18 @@ public class ASTToTargetAST { } } - List finalParams = params; - if (parameterSet.stream().noneMatch(p -> p.equals(finalParams))) { - List txParams = convert(method.getParameterList(), this.generics.txGenerics); + List txParams = convert(method.getParameterList(), this.generics.txGenerics); - var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method); - var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method); + var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method); + var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method); - var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); - var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); - var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature); - result.add(newMethod); - parameterSet.add(params); - } + var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); + var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); + var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature); + + var concreteParams = tphsInMethods.getOrDefault(method, new HashSet<>()).stream().map(sig -> new SignaturePairTarget(convert(sig.signature), convert(sig.parameter))).toList(); + + result.add(new MethodWithTphs(newMethod, concreteParams)); } return result; diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 7e50585a..b94c37cd 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -208,6 +208,11 @@ public class StatementToTargetExpression implements ASTVisitor { var isPrivate = false; var signature = methodCall.signatureArguments().stream().map(converter::convert).toList(); + // Add used TPHs to containing method + for (var i = 0; i < methodCall.signatureArguments().size(); i++) { + converter.addSignaturePair(methodCall.signatureArguments().get(i), methodCall.arglist.getArguments().get(i).getType()); + } + var receiverClass = converter.compiler.getClass(receiverName); if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) { if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!"); diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 7ca70857..5638e64a 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -1126,6 +1126,13 @@ public class TestComplete { var instance = clazz.getDeclaredConstructor().newInstance(); } + @Test + public void testBug332() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug332.jav"); + var clazz = classFiles.get("Bug332"); + var instance = clazz.getDeclaredConstructor().newInstance(); + } + @Test public void testBug333() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug333.jav");