Skip to content

Commit

Permalink
Fixes for type attribution and TypeUtils#isAssignableTo() (#4427)
Browse files Browse the repository at this point in the history
* Fixes for type attribution and `TypeUtils#isAssignableTo()`

Try to fix #4423 by correcting the type attribution for some generics and the corresponding type assignability check.

Fixes: #4423

* Better type attribution for `Type.CapturedType`

* Replicate code changes to Java 8, 11 and 21

---------

Co-authored-by: Tim te Beek <[email protected]>
  • Loading branch information
knutwannheden and timtebeek authored Aug 21, 2024
1 parent 4404c55 commit a8f51ac
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,12 @@ private JavaType.GenericTypeVariable generic(Type.WildcardType wildcard, String
}

private JavaType generic(Type.TypeVar type, String signature) {
String name = type.tsym.name.toString();
String name;
if (type instanceof Type.CapturedType && ((Type.CapturedType) type).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = type.tsym.name.toString();
}
JavaType.GenericTypeVariable gtv = new JavaType.GenericTypeVariable(null,
name, INVARIANT, null);
typeCache.put(signature, gtv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.openrewrite.java.isolated;

import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
Expand Down Expand Up @@ -51,7 +52,7 @@ private String signature(@Nullable Type type) {
return ((Type.ClassType) type).typarams_field != null && ((Type.ClassType) type).typarams_field.length() > 0 ? parameterizedSignature(type) : classSignature(type);
}
} else if (type instanceof Type.CapturedType) { // CapturedType must be evaluated before TypeVar
return signature(((Type.CapturedType) type).wildcard);
return genericSignature(type);
} else if (type instanceof Type.TypeVar) {
return genericSignature(type);
} else if (type instanceof Type.JCPrimitiveType) {
Expand Down Expand Up @@ -140,7 +141,12 @@ public String classSignature(Object type) {
@Override
public String genericSignature(Object type) {
Type.TypeVar generic = (Type.TypeVar) type;
String name = generic.tsym.name.toString();
String name;
if (generic instanceof Type.CapturedType && ((Type.CapturedType) generic).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = generic.tsym.name.toString();
}

if (typeVariableNameStack == null) {
typeVariableNameStack = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,12 @@ private JavaType.GenericTypeVariable generic(Type.WildcardType wildcard, String
}

private JavaType generic(Type.TypeVar type, String signature) {
String name = type.tsym.name.toString();
String name;
if (type instanceof Type.CapturedType && ((Type.CapturedType) type).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = type.tsym.name.toString();
}
JavaType.GenericTypeVariable gtv = new JavaType.GenericTypeVariable(null,
name, INVARIANT, null);
typeCache.put(signature, gtv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.openrewrite.java.isolated;

import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
Expand Down Expand Up @@ -51,7 +52,7 @@ private String signature(@Nullable Type type) {
return ((Type.ClassType) type).typarams_field != null && ((Type.ClassType) type).typarams_field.length() > 0 ? parameterizedSignature(type) : classSignature(type);
}
} else if (type instanceof Type.CapturedType) { // CapturedType must be evaluated before TypeVar
return signature(((Type.CapturedType) type).wildcard);
return genericSignature(type);
} else if (type instanceof Type.TypeVar) {
return genericSignature(type);
} else if (type instanceof Type.JCPrimitiveType) {
Expand Down Expand Up @@ -140,7 +141,12 @@ public String classSignature(Object type) {
@Override
public String genericSignature(Object type) {
Type.TypeVar generic = (Type.TypeVar) type;
String name = generic.tsym.name.toString();
String name;
if (generic instanceof Type.CapturedType && ((Type.CapturedType) generic).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = generic.tsym.name.toString();
}

if (typeVariableNameStack == null) {
typeVariableNameStack = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ReloadableJava21TypeMapping implements JavaTypeMapping<Tree> {

public JavaType type(com.sun.tools.javac.code.@Nullable Type type) {
if (type == null || type instanceof Type.ErrorType || type instanceof Type.PackageType || type instanceof Type.UnknownType ||
type instanceof NullType) {
type instanceof NullType) {
return JavaType.Class.Unknown.getInstance();
}

Expand Down Expand Up @@ -211,7 +211,12 @@ private JavaType.GenericTypeVariable generic(Type.WildcardType wildcard, String
}

private JavaType generic(Type.TypeVar type, String signature) {
String name = type.tsym.name.toString();
String name;
if (type instanceof Type.CapturedType && ((Type.CapturedType) type).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = type.tsym.name.toString();
}
JavaType.GenericTypeVariable gtv = new JavaType.GenericTypeVariable(null,
name, INVARIANT, null);
typeCache.put(signature, gtv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.openrewrite.java.isolated;

import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
Expand Down Expand Up @@ -51,7 +52,7 @@ private String signature(@Nullable Type type) {
return ((Type.ClassType) type).typarams_field != null && ((Type.ClassType) type).typarams_field.length() > 0 ? parameterizedSignature(type) : classSignature(type);
}
} else if (type instanceof Type.CapturedType) { // CapturedType must be evaluated before TypeVar
return signature(((Type.CapturedType) type).wildcard);
return genericSignature(type);
} else if (type instanceof Type.TypeVar) {
return genericSignature(type);
} else if (type instanceof Type.JCPrimitiveType) {
Expand Down Expand Up @@ -140,7 +141,12 @@ public String classSignature(Object type) {
@Override
public String genericSignature(Object type) {
Type.TypeVar generic = (Type.TypeVar) type;
String name = generic.tsym.name.toString();
String name;
if (generic instanceof Type.CapturedType && ((Type.CapturedType) generic).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = generic.tsym.name.toString();
}

if (typeVariableNameStack == null) {
typeVariableNameStack = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,12 @@ private JavaType.GenericTypeVariable generic(Type.WildcardType wildcard, String
}

private JavaType generic(Type.TypeVar type, String signature) {
String name = type.tsym.name.toString();
String name;
if (type instanceof Type.CapturedType && ((Type.CapturedType) type).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = type.tsym.name.toString();
}
JavaType.GenericTypeVariable gtv = new JavaType.GenericTypeVariable(null,
name, INVARIANT, null);
typeCache.put(signature, gtv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.openrewrite.java;

import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
Expand Down Expand Up @@ -49,8 +50,8 @@ private String signature(@Nullable Type type) {
} catch (Symbol.CompletionFailure ignored) {
return ((Type.ClassType) type).typarams_field != null && ((Type.ClassType) type).typarams_field.length() > 0 ? parameterizedSignature(type) : classSignature(type);
}
} else if (type instanceof Type.CapturedType) { // CapturedType must be evaluated before TypeVar
return signature(((Type.CapturedType) type).wildcard);
} else if (type instanceof Type.CapturedType) { // CapturedType must be evaluated before TypeVar
return genericSignature(type);
} else if (type instanceof Type.TypeVar) {
return genericSignature(type);
} else if (type instanceof Type.JCPrimitiveType) {
Expand Down Expand Up @@ -139,7 +140,12 @@ public String classSignature(Object type) {
@Override
public String genericSignature(Object type) {
Type.TypeVar generic = (Type.TypeVar) type;
String name = generic.tsym.name.toString();
String name;
if (generic instanceof Type.CapturedType && ((Type.CapturedType) generic).wildcard.kind == BoundKind.UNBOUND) {
name = "?";
} else {
name = generic.tsym.name.toString();
}

if (typeVariableNameStack == null) {
typeVariableNameStack = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Issue;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.marker.SearchResult;
Expand All @@ -28,6 +29,48 @@

class JavaTemplateMatchTest implements RewriteTest {

@Test
@Issue("https://github.com/openrewrite/rewrite-templating/pull/91")
void shouldMatchAbstractStringAssertIsEqualToEmptyString() {
rewriteRun(
spec -> spec
.parser(JavaParser.fromJavaVersion().classpath("assertj-core"))
.recipe(toRecipe(() -> new JavaIsoVisitor<>() {
// Mimics what we saw in rewrite-templating
final JavaTemplate before = JavaTemplate
.builder("#{stringAssert:any(org.assertj.core.api.AbstractStringAssert<?>)}.isEqualTo(\"\");")
.javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
.build();

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
J.MethodInvocation mi = super.visitMethodInvocation(method, ctx);
return before.matches(getCursor()) ? SearchResult.found(mi) : mi;
}
})),
//language=java
java(
"""
import static org.assertj.core.api.Assertions.assertThat;
class Foo {
void test() {
assertThat("foo").isEqualTo("");
}
}
""",
"""
import static org.assertj.core.api.Assertions.assertThat;
class Foo {
void test() {
/*~~>*/assertThat("foo").isEqualTo("");
}
}
"""
)
);

}

@DocumentExample
@SuppressWarnings({"ConstantValue", "ConstantConditions"})
@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ public static boolean isAssignableTo(@Nullable JavaType to, @Nullable JavaType f
}
return !(from instanceof JavaType.GenericTypeVariable) && isAssignableTo(toFq.getFullyQualifiedName(), from);
} else if (to instanceof JavaType.GenericTypeVariable) {
if (from instanceof JavaType.GenericTypeVariable && isOfType(to, from)) {
return true;
}
JavaType.GenericTypeVariable toGeneric = (JavaType.GenericTypeVariable) to;
List<JavaType> toBounds = toGeneric.getBounds();
if (!toGeneric.getName().equals("?")) {
Expand Down

0 comments on commit a8f51ac

Please sign in to comment.