Skip to content

Commit

Permalink
fix: fix nested class field read problem (#3335)
Browse files Browse the repository at this point in the history
  • Loading branch information
slarse committed Apr 20, 2020
1 parent e060bd2 commit f3d1677
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ CtExpression<?> createTargetFieldAccess(QualifiedNameReference qualifiedNameRefe
} else if (ref.isStatic()) {
target = createTypeAccess(qualifiedNameReference, ref);
} else if (!ref.isStatic() && !ref.getDeclaringType().isAnonymous()) {
if (ref.getDeclaringType().getDeclaredField(ref.getSimpleName()) == null) {
if (!JDTTreeBuilderQuery.isResolvedField(qualifiedNameReference)) {
target = createTypeAccessNoClasspath(qualifiedNameReference);
} else {
target = jdtTreeBuilder.getFactory().Code().createThisAccess(jdtTreeBuilder.getReferencesBuilder().<Object>getTypeReference(qualifiedNameReference.actualReceiverType), true);
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/spoon/support/compiler/jdt/JDTTreeBuilderQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@ static boolean isValidProblemBindingField(QualifiedNameReference qualifiedNameRe
((FieldBinding) qualifiedNameReference.binding).declaringClass.compoundName);
}

/**
* Check if the name reference is resolved in the JDT tree, i.e. that the declaration is available.
*
* @param qualifiedNameReference
* Reference which should contain a field binding.
* @return true if the field has been resolved by the jdt builder.
*/
static boolean isResolvedField(QualifiedNameReference qualifiedNameReference) {
return qualifiedNameReference.binding instanceof FieldBinding
&& ((FieldBinding) qualifiedNameReference.binding).original().sourceField() != null;
}


/**
* Checks if the last node in the stack in the context is an assignment and have a lhs equals to the given expression.
*
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/spoon/test/targeted/TargetedExpressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,22 @@ public void testOnlyStaticTargetFieldReadNoClasspath() {
assertEquals("Launcher", ((CtTypeAccess<?>) target).getAccessedType().getSimpleName());
}

@Test
public void testNestedClassAccessEnclosingTypeFieldNoClasspath() {
// Checks that a nested class accessing a field of an enclosing type's non-static field correctly
// resolves to a non-static field access. See https://github.com/INRIA/spoon/issues/3334 for details.
final Launcher launcher = new Launcher();
launcher.getEnvironment().setNoClasspath(true);
launcher.addInputResource("./src/test/resources/spoon/test/noclasspath/targeted/Outer.java");
CtModel model = launcher.buildModel();

List<CtFieldRead<?>> fieldReads = model.getElements(e -> e.getVariable().getSimpleName().equals("cls"));
assertEquals(1, fieldReads.size());
CtFieldRead<?> fieldRead = fieldReads.get(0);

assertTrue(fieldRead.getTarget() instanceof CtThisAccess);
}

@Test
public void testTargetsOfInv() throws Exception {
// contract: Specify declaring type of the executable of an invocation, the target of the invocation and its result.
Expand Down
9 changes: 9 additions & 0 deletions src/test/resources/spoon/test/noclasspath/targeted/Outer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
public class Outer {
SomeClass cls = new SomeClass();

private class Inner {
public void testMethod() {
int a = cls.val;
}
}
}

0 comments on commit f3d1677

Please sign in to comment.