Implement ThisCall (fix #295)

This commit is contained in:
Daniel Holle 2024-03-18 13:29:53 +01:00
parent c07d4d36e9
commit 0acfe6c0d4
12 changed files with 91 additions and 12 deletions

View File

@ -0,0 +1,18 @@
import java.lang.Integer;
public class Bug295 {
public Integer a;
public Integer b;
public Integer c;
public Bug295(a, b, c) {
this(a);
this.b = b;
this.c = c;
}
public Bug295(a) {
this.a = a;
}
}

View File

@ -717,6 +717,8 @@ public class StatementGenerator {
MethodCall ret;
if (expr.SUPER() != null) {
ret = new SuperCall(argumentList, TypePlaceholder.fresh(offset), signature, offset);
} else if(expr.THIS() != null) {
ret = new ThisCall(argumentList, TypePlaceholder.fresh(offset), signature, offset);
} else {
ret = new MethodCall(TypePlaceholder.fresh(offset), getReceiver(receiver), name, argumentList, TypePlaceholder.fresh(offset), signature, offset);
}

View File

@ -451,7 +451,7 @@ public class SyntaxTreeGenerator {
protected static Block prepareBlock(Block constructorBlock, RefType superClass) {
List<Statement> statements = constructorBlock.getStatements();
if (statements.isEmpty() || !(statements.get(0) instanceof SuperCall)) {
if (statements.isEmpty() || !(statements.get(0) instanceof SuperCall || statements.get(0) instanceof ThisCall)) {
var signature = new ArrayList<RefTypeOrTPHOrWildcardOrGeneric>();
signature.add(new Void(new NullToken()));
statements.add(0, new SuperCall(superClass, signature, constructorBlock.getOffset()));

View File

@ -286,6 +286,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
this.visit((MethodCall) superCall);
}
@Override
public void visit(ThisCall thisCall) {
}
@Override
public void visit(Switch switchStmt) {
switchStmt.getSwitch().accept(this);

View File

@ -71,6 +71,8 @@ public interface StatementVisitor {
void visit(SuperCall superCall);
void visit(ThisCall thisCall);
void visit(ExpressionReceiver expressionReceiver);
void visit(UnaryExpr unaryExpr);

View File

@ -1,20 +1,24 @@
package de.dhbwstuttgart.syntaxtree.statement;
import de.dhbwstuttgart.syntaxtree.Constructor;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.Void;
import org.antlr.v4.runtime.Token;
import java.util.ArrayList;
public class ThisCall extends MethodCall
{
public ThisCall(Receiver receiver, ArgumentList arglist, int offset)
{
// TODO What is this?
super(null, null, null, null, null, null, null);
public ThisCall(ArgumentList argumentList, RefTypeOrTPHOrWildcardOrGeneric receiverType, ArrayList<RefTypeOrTPHOrWildcardOrGeneric> argTypes, Token offset) {
super(new Void(offset), new ExpressionReceiver(new This(offset)), "<init>", argumentList, receiverType, argTypes, offset);
}
public ArgumentList arglist;
@Override
public void accept(StatementVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -382,6 +382,13 @@ public class OutputGenerator implements ASTVisitor {
out.append(")");
}
@Override
public void visit(ThisCall thisCall) {
out.append("this(");
thisCall.arglist.accept(this);
out.append(")");
}
@Override
public void visit(ExpressionReceiver receiver) {
receiver.expr.accept(this);

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
@ -290,6 +291,15 @@ public class StatementToTargetExpression implements ASTVisitor {
result = new TargetMethodCall(type, type, parameters, new TargetSuper(aSuper), superCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), aSuper, superCall.name, false, false);
}
@Override
public void visit(ThisCall thisCall) {
var aThis = converter.convert(new RefType(converter.currentClass.getClassName(), new NullToken()));
var type = converter.convert(thisCall.getType());
var parameters = thisCall.arglist.getArguments().stream().map(par -> converter.convert(par.getType())).toList();
result = new TargetMethodCall(type, type, parameters, new TargetThis(aThis), thisCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), aThis, thisCall.name, false, false);
}
@Override
public void visit(ExpressionReceiver expressionReceiver) {
result = converter.convert(expressionReceiver.expr);

View File

@ -1,12 +1,18 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.*;
// This visitor walks the entire tree, individual methods may be overridden
public abstract class TracingStatementVisitor implements StatementVisitor {
@Override
public void visit(ThisCall thisCall) {
visit((MethodCall) thisCall);
}
@Override
public void visit(MethodCall methodCall) {
methodCall.receiver.accept(this);
@ -155,7 +161,7 @@ public abstract class TracingStatementVisitor implements StatementVisitor {
@Override
public void visit(SuperCall superCall) {
visit((MethodCall) superCall);
}
@Override

View File

@ -564,7 +564,7 @@ public class TYPEStmt implements StatementVisitor {
for (var ctor : clazz.getConstructors()) {
var params = convertParams(ctor.getParameterList(), info);
if (params.size() != superCall.arglist.getArguments().size()) continue;
var assumption = new MethodAssumption(null, new Void(new NullToken()), params, createTypeScope(clazz, ctor), ctor.isInherited);
var assumption = new MethodAssumption(clazz, new Void(new NullToken()), params, createTypeScope(clazz, ctor), ctor.isInherited);
GenericsResolver resolver = getResolverInstance();
Set<Constraint<Pair>> oneMethodConstraints = generateConstraint(superCall, assumption, info, resolver);
@ -576,6 +576,21 @@ public class TYPEStmt implements StatementVisitor {
constraintsSet.addOderConstraint(methodConstraints);
}
@Override
public void visit(ThisCall thisCall) {
Set<Constraint<Pair>> methodConstraints = new HashSet<>();
for (var ctor : info.getCurrentClass().getConstructors()) {
var params = convertParams(ctor.getParameterList(), info);
if (params.size() != thisCall.arglist.getArguments().size()) continue;
var assumption = new MethodAssumption(info.getCurrentClass(), new Void(new NullToken()), params, createTypeScope(info.getCurrentClass(), ctor), ctor.isInherited);
GenericsResolver resolver = getResolverInstance();
Set<Constraint<Pair>> oneMethodConstraints = generateConstraint(thisCall, assumption, info, resolver);
methodConstraints.addAll(oneMethodConstraints);
}
constraintsSet.addOderConstraint(methodConstraints);
}
/*
* METHOD CALL Section:
*/

View File

@ -941,6 +941,16 @@ public class TestComplete {
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testBug295() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug295.jav");
var clazz = classFiles.get("Bug295");
var instance = clazz.getDeclaredConstructor(Integer.class, Integer.class, Integer.class).newInstance(1, 2, 3);
assertEquals(clazz.getDeclaredField("a").get(instance), 1);
assertEquals(clazz.getDeclaredField("b").get(instance), 2);
assertEquals(clazz.getDeclaredField("c").get(instance), 3);
}
@Test
public void testBug296() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug296.jav");