Skip to content

Commit

Permalink
fix: Unqualified static method calls should be implicit (#3371)
Browse files Browse the repository at this point in the history
  • Loading branch information
slarse committed May 18, 2020
1 parent 3a8d04d commit 8498c0e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -640,11 +640,8 @@ <T> CtTypeAccess<T> createTypeAccessNoClasspath(SingleNameReference singleNameRe
typeReference.setSimpleName(CharOperation.charToString(singleNameReference.binding.readableName()));
}
CtReference packageOrDeclaringType = jdtTreeBuilder.getReferencesBuilder().getDeclaringReferenceFromImports(singleNameReference.token);
if (packageOrDeclaringType != null) {
// must be implicit as a SingleNameReference is not qualified, see #3363
packageOrDeclaringType.setImplicit(true);
}
jdtTreeBuilder.getReferencesBuilder().setPackageOrDeclaringType(typeReference, packageOrDeclaringType);
// package/declaring type must be added as implicit as a SingleNameReference is not qualified, see #3363 and #3370
jdtTreeBuilder.getReferencesBuilder().setImplicitPackageOrDeclaringType(typeReference, packageOrDeclaringType);
return jdtTreeBuilder.getFactory().Code().createTypeAccess(typeReference);
}

Expand Down
23 changes: 23 additions & 0 deletions src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,29 @@ void setPackageOrDeclaringType(CtTypeReference<?> ref, CtReference declaring) {
}
}

/**
* Same as {@link #setPackageOrDeclaringType(CtTypeReference, CtReference)}, but ensures that the set declaring
* type or package reference is made implicit.
*
* NOTE: Only a package/declaring type that's set by this method is made implicit, pre-existing references are
* not modified (but they may be replaced).
*/
void setImplicitPackageOrDeclaringType(CtTypeReference<?> ref, CtReference declaring) {
CtTypeReference<?> oldDeclaring = ref.getDeclaringType();
CtPackageReference oldPackage = ref.getPackage();

setPackageOrDeclaringType(ref, declaring);
CtTypeReference<?> currentDeclaring = ref.getDeclaringType();
CtPackageReference currentPackage = ref.getPackage();

if (currentDeclaring != oldDeclaring) {
currentDeclaring.setImplicit(true);
}
if (currentPackage != oldPackage) {
currentPackage.setImplicit(true);
}
}

private static boolean containsStarImport(ImportReference[] imports) {
return imports != null && Arrays.stream(imports).anyMatch(imp -> imp.toString().endsWith("*"));
}
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/spoon/test/targeted/TargetedExpressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtFieldReference;
import spoon.reflect.reference.CtPackageReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.filter.NamedElementFilter;
import spoon.reflect.visitor.filter.TypeFilter;
Expand Down Expand Up @@ -482,6 +483,24 @@ public void testInitializeFieldAccessInNoclasspathMode() {
assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(expectedThisAccess).result("this.bar"), elements.get(0));
}

@Test
public void testUnqualifiedStaticMethodCallNoclasspath() {
// contract: If a static method of some other type is accessed without qualification, any qualification attached
// to it must be implicit. See #3370 for details
final Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/resources/noclasspath/UnqualifiedStaticMethodCall.java");
launcher.getEnvironment().setNoClasspath(true);
CtModel model = launcher.buildModel();
List<CtTypeAccess<?>> typeAccesses = model.getElements(e -> e.getAccessedType().getSimpleName().equals("SomeClass"));

assertEquals("There should only be one reference to SomeClass, check the resource!", 1, typeAccesses.size());

CtPackageReference pkg = typeAccesses.get(0).getAccessedType().getPackage();

assertEquals("pkg", pkg.getSimpleName());
assertTrue(pkg.isImplicit());
}

@Test
public void testClassDeclaredInALambda() throws Exception {
// contract: A class can be declared in a lambda expression where we use final fields.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg;

class UnqualifiedStaticMethodCall {
public static void main(String[] args) {
SomeClass.someMethod(args);
}
}

0 comments on commit 8498c0e

Please sign in to comment.