Compare commits

..
10 Commits
Author SHA1 Message Date
dholle d5c0d653d2 Add test for a merge stort
SonarQube Scan / SonarQube Trigger (push) Failing after 1m18s
2026-08-28 18:25:20 +02:00
dholle f7e5a1f8a2 Fix log directory getting deleted, but logger should create it
SonarQube Scan / SonarQube Trigger (push) Failing after 1m17s
2026-08-28 13:21:32 +02:00
dholle 8f6e6e1980 Fix one of the tests 2026-08-28 13:20:58 +02:00
dholle 912f3d381e Fix pattern matching
SonarQube Scan / SonarQube Trigger (push) Failing after 59s
2026-08-28 13:02:53 +02:00
dholle 7e24bbd552 Give error on duplicate fields
SonarQube Scan / SonarQube Trigger (push) Failing after 1m0s
2026-08-27 18:34:24 +02:00
dholle 50f2572644 Also add receiver type to method call disambiguation
SonarQube Scan / SonarQube Trigger (push) Failing after 58s
2026-08-27 17:48:31 +02:00
dholle e1518c8b37 Merge branch 'master' of ssh://gitea.hb.dhbw-stuttgart.de:2222/JavaTX/JavaCompilerCore
SonarQube Scan / SonarQube Trigger (push) Failing after 1m17s
2026-08-27 11:36:23 +02:00
dholle f7a85db191 Discard method calls that are less specific to preserve Java semantics, see #402 2026-08-27 11:36:16 +02:00
dholle 41d5f661e1 Merge branch 'master' of https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore
SonarQube Scan / SonarQube Trigger (push) Failing after 1m37s
2026-08-25 11:14:53 +02:00
dholle b7f46c428f Add recursive call for BoolExpression 2026-08-25 11:14:27 +02:00
13 changed files with 121 additions and 51 deletions
@@ -1,11 +1,9 @@
import java.lang.String; import java.lang.String;
import java.lang.Integer; import java.lang.Integer;
sealed interface List permits LinkedElem, Elem {} sealed interface List<T> permits LinkedElem, Elem {}
public record LinkedElem<T>(T a, List<T> l) implements List<T>{}
public record Elem<T>(T c) implements List<T>{}
public record LinkedElem<T>(T a,List l) implements List{}
public record Elem<T>(T c) implements List{}
public class GenericRecordSwitchCase { public class GenericRecordSwitchCase {
public main(o) { public main(o) {
+3 -1
View File
@@ -5,6 +5,8 @@ import java.lang.Object;
public class HelloWorld { public class HelloWorld {
public static hello() { public static hello() {
System.out.println((Object)"Hello World!"); System.out.println("Hello World!");
System.out.println("Bye World!");
System.out.println("The end!");
} }
} }
+18 -16
View File
@@ -1,23 +1,25 @@
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.lang.String; import java.lang.Integer;
public class Sorting{ public class Sorting {
merge(a, b){ List<Integer> merge(List<Integer> a, List<Integer> b) {
a.addAll(b); var r = new ArrayList<>();
return a; for (var i = 0, j = 0; i < a.size() || j < b.size();)
if (j == b.size() || (i < a.size() && a.get(i) <= b.get(j)))
r.add(a.get(i++));
else r.add(b.get(j++));
return r;
} }
sort(in){ split(list) {
var firstHalf = in; var mid = list.size() / 2;
var secondHalf = in; return List.of(list.subList(0, mid), list.subList(mid, list.size()));
return merge(sort(firstHalf), sort(secondHalf)); }
}
public sort(in) {
/* if (in.size() <= 1) return in;
void sort(a){ var halves = split(in);
a = merge(a,a); return merge(sort(halves.get(0)), sort(halves.get(1)));
} }
*/
} }
@@ -350,6 +350,8 @@ public class Codegen {
} }
private TargetType largerType(TargetType left, TargetType right) { private TargetType largerType(TargetType left, TargetType right) {
if (left instanceof TargetExtendsWildcard wc) left = wc.innerType();
if (right instanceof TargetExtendsWildcard wc) right = wc.innerType();
if (left.equals(TargetType.String) || right.equals(TargetType.String)) { if (left.equals(TargetType.String) || right.equals(TargetType.String)) {
return TargetType.String; return TargetType.String;
} else if (left.equals(TargetType.Double) || right.equals(TargetType.Double)) { } else if (left.equals(TargetType.Double) || right.equals(TargetType.Double)) {
@@ -3,6 +3,6 @@ package de.dhbwstuttgart.exceptions;
public class DebugException extends RuntimeException { public class DebugException extends RuntimeException {
public DebugException(String message) { public DebugException(String message) {
System.err.print(message); super(message);
} }
} }
@@ -482,8 +482,8 @@ public class StatementGenerator {
IdentifierContext identifierCtx = recordPatternCtx.identifier(); IdentifierContext identifierCtx = recordPatternCtx.identifier();
var text = (identifierCtx != null) ? identifierCtx.getText() : null; var text = (identifierCtx != null) ? identifierCtx.getText() : null;
//Hier evtl. Typ anpassen -> wenn kein Typ bekannt ist push neuen Typ auf Hashtable //Hier evtl. Typ anpassen -> wenn kein Typ bekannt ist push neuen Typ auf Hashtable
var type = recordPatternCtx.type == null ? TypePlaceholder.fresh(recordPatternCtx.getStart()) : TypeGenerator.convert(recordPatternCtx.type, reg, generics);
var ctor = TypeGenerator.convert(recordPatternCtx.ctor, reg, generics); var ctor = TypeGenerator.convert(recordPatternCtx.ctor, reg, generics);
var type = recordPatternCtx.type == null ? ctor : TypeGenerator.convert(recordPatternCtx.type, reg, generics);
if (text != null) localVars.put(text, type); if (text != null) localVars.put(text, type);
var ret = new RecordPattern(subPattern, text, type, (RefType)ctor, recordPatternCtx.getStart()); var ret = new RecordPattern(subPattern, text, type, (RefType)ctor, recordPatternCtx.getStart());
return ret; return ret;
@@ -115,8 +115,10 @@ public class ASTToTargetAST {
public static Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList, IGenerics generics, JavaTXCompiler compiler) { public static Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList, IGenerics generics, JavaTXCompiler compiler) {
Optional<Method> method = Optional.empty(); Optional<Method> method = Optional.empty();
while (method.isEmpty()) { while (method.isEmpty()) {
method = owner.getMethods().stream().filter(m -> m.name.equals(name) && method = owner.getMethods().stream().filter(m -> {
parameterEquals(m.getParameterList().getFormalparalist().stream().map(p -> generics.getTargetType(p.getType())).toList(), argumentList)).findFirst(); return m.name.equals(name) &&
parameterEquals(m.getParameterList().getFormalparalist().stream().map(p -> generics.getTargetType(p.getType())).toList(), argumentList);
}).findFirst();
if (owner.getClassName().toString().equals("java.lang.Object")) break; if (owner.getClassName().toString().equals("java.lang.Object")) break;
owner = compiler.getClass(owner.getSuperClass().getName()); owner = compiler.getClass(owner.getSuperClass().getName());
} }
@@ -331,15 +333,16 @@ public class ASTToTargetAST {
var u_opt = unify(m, m1); var u_opt = unify(m, m1);
if (u_opt.isPresent()) { if (u_opt.isPresent()) {
var u = u_opt.get(); var u = u_opt.get();
//Target.logger.info("Unified " + m + " AND " + m1 + "\n\t" + u); //System.out.println("Unified " + m + " AND " + m1 + "\n\t" + u);
i.remove(m1); i.remove(m1);
R.remove(m); R.remove(m);
R.remove(m1); R.remove(m1);
R.add(u); R.add(u);
a.add(u); a.add(u);
} /*else { m = u;
Target.logger.info("Couldn't unify " + m + " AND " + m1); } else {
}*/ //System.out.println("Couldn't unify " + m + " AND " + m1);
}
} }
} }
} }
@@ -381,8 +384,21 @@ public class ASTToTargetAST {
TargetBlock finalFieldInitializer = fieldInitializer; TargetBlock finalFieldInitializer = fieldInitializer;
var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics, compiler)).toList(); var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics, compiler)).toList();
var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer, generics)).flatMap(List::stream).toList(); var constructors = input.getConstructors().stream().map(constructor -> {
var fields = input.getFieldDecl().stream().map(f -> convert(f, generics.javaGenerics)).toList(); try {
return this.convert(input, constructor, finalFieldInitializer, generics);
} catch (DiscardResultSet discard) {
return null;
}
}
).filter(Objects::nonNull).flatMap(List::stream).toList();
var fields = input.getFieldDecl().stream().map(f -> {
var possibleTypes = new HashSet<TargetType>();
for (var g : all) possibleTypes.add(convert(f.getType(), g.javaGenerics(), compiler));
if (possibleTypes.size() > 1)
compiler.warn(new CompilerWarning(f.getOffset(), "Multiple possible types for field " + f.getName() + ": " + possibleTypes + " please select one"));
return convert(f, generics.javaGenerics);
}).toList();
var m0 = groupMethods(input, input.getMethods()); var m0 = groupMethods(input, input.getMethods());
var m1 = new ArrayList<TargetMethod>(); var m1 = new ArrayList<TargetMethod>();
@@ -851,7 +867,13 @@ public class ASTToTargetAST {
for (var tph : tphs) { for (var tph : tphs) {
var left = a.getTargetType(tph); var left = a.getTargetType(tph);
var right = b.getTargetType(tph); var right = b.getTargetType(tph);
if (!Objects.equals(left, right)) return true; if (left instanceof TargetExtendsWildcard wc) left = wc.innerType();
if (right instanceof TargetExtendsWildcard wc) right = wc.innerType();
if (!Objects.equals(left, right)) {
System.out.println(tph + " " + left + " " + right);
return true;
}
} }
return false; return false;
} }
@@ -889,10 +911,13 @@ public class ASTToTargetAST {
signatures.add(new Signature(javaSignature, txSignature, generics)); signatures.add(new Signature(javaSignature, txSignature, generics));
} }
if (!signatures.isEmpty()) { for (var signature : new ArrayList<>(signatures)) {
var signature = signatures.getFirst(); try {
// We need to convert once to find out what TPHs are existing in the given method convert(new MethodWithTphs(method, signature.generics, signature));
convert(new MethodWithTphs(method, signature.generics, signature)); } catch (DiscardResultSet discard) {
// If a result set is discarded we skip it from now on
signatures.removeIf(s -> s == signature);
}
} }
for (var signature : signatures) { for (var signature : signatures) {
@@ -980,7 +1005,7 @@ public class ASTToTargetAST {
return null; return null;
} }
private boolean isSubtype(TargetType test, TargetType other) { public boolean isSubtype(TargetType test, TargetType other) {
if (other.equals(TargetType.Object)) return true; if (other.equals(TargetType.Object)) return true;
if (test instanceof TargetFunNType tfun && other instanceof TargetFunNType ofun) if (test instanceof TargetFunNType tfun && other instanceof TargetFunNType ofun)
return isSubtype(new FunNGenerator.GenericParameters(tfun), new FunNGenerator.GenericParameters(ofun)); return isSubtype(new FunNGenerator.GenericParameters(tfun), new FunNGenerator.GenericParameters(ofun));
@@ -989,6 +1014,12 @@ public class ASTToTargetAST {
var otherClass = compiler.getClass(new JavaClassName(other.name())); var otherClass = compiler.getClass(new JavaClassName(other.name()));
if (testClass == null) return false; if (testClass == null) return false;
while (testClass != null) { while (testClass != null) {
if (otherClass.isInterface()) {
for (var superInterface : testClass.getSuperInterfaces()) {
if (superInterface.getName().equals(otherClass.getClassName())) return true;
if (isSubtype(new TargetRefType(superInterface.getName().toString()), other)) return true;
}
}
if (testClass.equals(otherClass)) return true; if (testClass.equals(otherClass)) return true;
if (testClass.getClassName().equals(new JavaClassName("java.lang.Object"))) break; if (testClass.getClassName().equals(new JavaClassName("java.lang.Object"))) break;
testClass = compiler.getClass(testClass.getSuperClass().getName()); testClass = compiler.getClass(testClass.getSuperClass().getName());
@@ -0,0 +1,9 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import java.util.List;
public class DiscardResultSet extends RuntimeException {
public DiscardResultSet() {}
}
@@ -1008,7 +1008,9 @@ public abstract class GenerateGenerics implements IGenerics {
public TargetType getTargetType(RefTypeOrTPHOrWildcardOrGeneric in) { public TargetType getTargetType(RefTypeOrTPHOrWildcardOrGeneric in) {
if (in instanceof TypePlaceholder tph) { if (in instanceof TypePlaceholder tph) {
if (equality.containsKey(tph)) { if (equality.containsKey(tph)) {
return getTargetType(equality.get(tph)); var tph2 = equality.get(tph);
// Sanity check, they should not be equal!
if (!Objects.equals(in, tph2)) return getTargetType(tph2);
} }
var type = concreteTypes.get(new TPH(tph)); var type = concreteTypes.get(new TPH(tph));
if (type == null) return new TargetGenericType(tph.getName()); if (type == null) return new TargetGenericType(tph.getName());
@@ -1,5 +1,6 @@
package de.dhbwstuttgart.target.generate; package de.dhbwstuttgart.target.generate;
import com.google.common.collect.Iterables;
import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.exceptions.DebugException; import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.exceptions.NotImplementedException;
@@ -222,6 +223,19 @@ public class StatementToTargetExpression implements ASTVisitor {
@Override @Override
public void visit(MethodCall methodCall) { public void visit(MethodCall methodCall) {
// Look at the signature in all result sets and check if a more specific insertion exists.
// If so, discard this result set by throwing an exception
for (var tph : Iterables.concat(List.of(methodCall.receiver.getType()), methodCall.signatureArguments())) {
var currentType = converter.convert(tph, generics);
for (var g2 : converter.all) if (g2.javaGenerics() != generics) {
var type = g2.javaGenerics().getTargetType(tph);
if (!Objects.equals(type, currentType) && converter.isSubtype(type, currentType)) {
throw new DiscardResultSet();
}
}
}
var receiverType = converter.convert(methodCall.receiver.getType(), generics); var receiverType = converter.convert(methodCall.receiver.getType(), generics);
var isFunNType = receiverType instanceof TargetFunNType; var isFunNType = receiverType instanceof TargetFunNType;
@@ -250,18 +264,20 @@ public class StatementToTargetExpression implements ASTVisitor {
} else if (!isFunNType) { } else if (!isFunNType) {
receiverClass = converter.compiler.getClass(receiverName); receiverClass = converter.compiler.getClass(receiverName);
if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!"); if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!");
foundMethod = findMethod(receiverName, methodCall.name, signature, converter.compiler).orElseThrow(); foundMethod = findMethod(receiverName, methodCall.name, signature, converter.compiler).orElseThrow(
() -> new DebugException("Method " + methodCall.name + " not found (" + signature + ") on class " + receiverName)
);
} }
if (!isFunNType) { if (!isFunNType) {
returnType = converter.convert(foundMethod.getReturnType(), generics); // NOTE Not using the direct conversion method on converter to bypass adding the TPH to the used TPH list
returnType = ASTToTargetAST.convert(foundMethod.getReturnType(), generics, converter.compiler);
argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType(), generics)).toList(); argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType(), generics)).toList();
isStatic = Modifier.isStatic(foundMethod.modifier); isStatic = Modifier.isStatic(foundMethod.modifier);
isPrivate = Modifier.isPrivate(foundMethod.modifier); isPrivate = Modifier.isPrivate(foundMethod.modifier);
isInterface = receiverClass.isInterface(); isInterface = receiverClass.isInterface();
} }
//System.out.println(argList);
result = new TargetMethodCall( result = new TargetMethodCall(
converter.convert(methodCall.getType(), generics), returnType, argList, converter.convert(methodCall.getType(), generics), returnType, argList,
converter.convert(methodCall.receiver, generics), converter.convert(methodCall.receiver, generics),
@@ -392,6 +392,8 @@ public class TYPEStmt implements StatementVisitor {
@Override @Override
public void visit(BoolExpression expr) { public void visit(BoolExpression expr) {
expr.lexpr.accept(this);
expr.rexpr.accept(this);
constraintsSet.addUndConstraint(new Pair(bool, expr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset()))); constraintsSet.addUndConstraint(new Pair(bool, expr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset())));
constraintsSet.addUndConstraint(new Pair(bool, expr.lexpr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset()))); constraintsSet.addUndConstraint(new Pair(bool, expr.lexpr.getType(), PairOperator.EQUALSDOT, loc(expr.getOffset())));
@@ -32,14 +32,12 @@ public class Logger {
private static Writer defaultWriter; private static Writer defaultWriter;
private static void initLogger() { private static void initLogger() {
if (defaultWriter != null) return; if (defaultWriter != null) return;
if (ConsoleInterface.writeLogFiles) { if (!ConsoleInterface.writeLogFiles) return;
try { try {
Files.createDirectories(logFolder.toPath()); Files.createDirectories(logFolder.toPath());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Could not create directory for log files: " + logFolder, e); throw new RuntimeException("Could not create directory for log files: " + logFolder, e);
}
} }
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"); var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
var currentTimestamp = LocalDateTime.now().format(formatter); var currentTimestamp = LocalDateTime.now().format(formatter);
try { try {
+10 -2
View File
@@ -320,9 +320,17 @@ public class TestComplete {
} }
@Test @Test
public void overloadingSortingTest() throws Exception { public void sortingTest() throws Exception {
var classFiles = generateClassFiles(createClassLoader(), "Sorting.jav"); var classFiles = generateClassFiles(createClassLoader(), "Sorting.jav");
var instance = classFiles.get("Sorting").getDeclaredConstructor().newInstance(); var Sorting = classFiles.get("Sorting");
var instance = Sorting.getDeclaredConstructor().newInstance();
var unsorted = List.of(10, 2, 1, 20, -1, 5);
var sorted = List.of(-1, 1, 2, 5, 10, 20);
var sort = Sorting.getDeclaredMethod("sort", List.class);
var result = sort.invoke(instance, unsorted);
assertEquals(sorted, result);
} }
@Test @Test