Skip to content

Commit

Permalink
fix: Use CtSuperAccess when implicitly accessing superclass field (#5406
Browse files Browse the repository at this point in the history
)
  • Loading branch information
I-Al-Istannen authored Oct 4, 2023
1 parent af5f2c5 commit 30c6186
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public static IntExpr getTargetValue(Context context, Map<CtReference, Expr> var
targets.addFirst(target);
target = ((CtTargetedExpression) target).getTarget();
}
targets.addFirst(target);
if (target != null) {
targets.addFirst(target);
}

// Traverse all targets left to right
IntExpr targetValue = null;
Expand All @@ -45,6 +47,9 @@ else if (t instanceof CtArrayRead)
Expr arrayIndex = (Expr) index.getMetadata("value");
targetValue = (IntExpr) memory.readArray((CtArrayTypeReference) arrayRead.getTarget().getType(), targetValue, arrayIndex);
}
else if (t instanceof CtSuperAccess) {
targetValue = context.mkInt(Memory.thisPointer());
}
else if (t instanceof CtVariableRead)
{
targetValue = (IntExpr) variablesMap.get(((CtVariableRead) t).getVariable());
Expand Down
8 changes: 8 additions & 0 deletions spoon-smpl/src/main/java/spoon/smpl/SmPLMethodCFG.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ private void replace(CtElement e) {
* @param e Element about to be replaced
*/
private void logReplacementWarning(CtElement e) {
if (!e.getPosition().isValidPosition()) {
String code = e.toString();
LoggerFactory.getLogger("spoon-smpl")
.warn("Unsupported element excluded from control flow graph at unknown location: "
+ e.getClass().getSimpleName()
+ code.substring(0, Math.min(40, code.length())));
return;
}
String file = Optional.ofNullable(e.getPosition())
.map(x -> x.getFile())
.map(x -> x.getName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,9 @@ public <T> void visitCtThisAccess(CtThisAccess<T> thisAccess) {

@Override
public <T> void visitCtSuperAccess(CtSuperAccess<T> f) {
if (f.isImplicit()) {
return;
}
enterCtExpression(f);
if (f.getTarget() != null) {
scan(f.getTarget());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtNewClass;
import spoon.reflect.code.CtSuperAccess;
import spoon.reflect.code.CtTargetedExpression;
import spoon.reflect.code.CtThisAccess;
import spoon.reflect.code.CtTypeAccess;
Expand Down Expand Up @@ -96,8 +97,8 @@ protected void handleTargetedExpression(CtTargetedExpression<?, ?> targetedExpre
if (!target.isImplicit()) {
return;
}
if (target instanceof CtThisAccess) {
//the non implicit this access is not forced
if (target instanceof CtThisAccess || target instanceof CtSuperAccess) {
//the implicit this/super access is not forced
return;
}
if (target instanceof CtTypeAccess) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,18 @@ <T> CtFieldAccess<T> createFieldAccess(SingleNameReference singleNameReference)
if (ref.isStatic() && !ref.getDeclaringType().isAnonymous()) {
va.setTarget(jdtTreeBuilder.getFactory().Code().createTypeAccess(ref.getDeclaringType(), true));
} else if (!ref.isStatic()) {
va.setTarget(jdtTreeBuilder.getFactory().Code().createThisAccess(jdtTreeBuilder.getReferencesBuilder().getTypeReference(singleNameReference.actualReceiverType), true));
TypeBinding fieldDeclarerType = singleNameReference.fieldBinding().declaringClass;
TypeBinding actualReceiverType = singleNameReference.actualReceiverType;
CtTypeReference<?> owningType = jdtTreeBuilder.getReferencesBuilder().getTypeReference(fieldDeclarerType);
if (Arrays.equals(fieldDeclarerType.qualifiedSourceName(), actualReceiverType.qualifiedSourceName())) {
va.setTarget(jdtTreeBuilder.getFactory().Code().createThisAccess(owningType, true));
} else {
va.setTarget(
jdtTreeBuilder.getFactory().createSuperAccess()
.setType(owningType)
.setImplicit(true)
);
}
}
}
return va;
Expand Down
33 changes: 30 additions & 3 deletions src/test/java/spoon/test/targeted/TargetedExpressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
package spoon.test.targeted;


import java.util.List;

import org.junit.jupiter.api.Test;

import spoon.Launcher;
import spoon.reflect.CtModel;
import spoon.reflect.code.CtExpression;
Expand All @@ -44,6 +41,7 @@
import spoon.reflect.visitor.filter.NamedElementFilter;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.support.comparator.CtLineElementComparator;
import spoon.support.compiler.VirtualFile;
import spoon.support.reflect.code.CtConstructorCallImpl;
import spoon.support.reflect.code.CtFieldReadImpl;
import spoon.support.reflect.code.CtThisAccessImpl;
Expand All @@ -56,6 +54,8 @@
import spoon.test.targeted.testclasses.Tapas;
import spoon.testing.utils.ModelTest;

import java.util.List;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down Expand Up @@ -539,6 +539,33 @@ public void testClassDeclaredInALambda() throws Exception {
assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(thirdExpectedInner).target(expectedThisAccess).type(CtFieldWrite.class).result("this.index").isLocal(), elements.get(2));
}

@Test
void testUnqualifiedSuperFieldAccess() {
// contract: Unqualified super field accesses are modeled by an implicit CtSuperAccess
Launcher launcher = new Launcher();

launcher.getEnvironment().setComplianceLevel(17);
launcher.addInputResource(new VirtualFile(
"class A {\n" +
" int a;\n" +
"}\n" +
"\n" +
"class B extends A {\n" +
" void foo() {\n" +
" super.a = a;\n" +
" }\n" +
"}\n"
));

CtModel ctModel = launcher.buildModel();

CtFieldRead<?> read = ctModel.getElements(new TypeFilter<>(CtFieldRead.class)).get(0);
assertTrue(read.getTarget() instanceof CtSuperAccess<?>, "Target was no super access");
assertTrue(read.getTarget().isImplicit(), "super target was not implicit");
assertEquals("A", read.getTarget().getType().getQualifiedName());
assertEquals(read.toString(), "a", "super target was still printed");
}

private void assertEqualsFieldAccess(ExpectedTargetedExpression expected, CtFieldAccess<?> fieldAccess) {
if (expected.declaringType == null) {
assertNull(fieldAccess.getVariable().getDeclaringType());
Expand Down

0 comments on commit 30c6186

Please sign in to comment.