Skip to content

Commit

Permalink
Support mapping of generic thrown exception types (#4813)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkschneider authored Dec 25, 2024
1 parent 4ca0c8e commit 15740e4
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ private JavaType genericType(GenericsType g, String signature) {
}
}

List<JavaType.FullyQualified> thrownExceptions = null;
List<JavaType> thrownExceptions = null;
if(node.getExceptions() != null) {
for (ClassNode e : node.getExceptions()) {
thrownExceptions = new ArrayList<>(node.getExceptions().length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ public JavaType.Primitive primitive(TypeTag tag) {

JavaType returnType = null;
List<JavaType> parameterTypes = null;
List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

if (selectType instanceof Type.MethodType) {
Type.MethodType methodType = (Type.MethodType) selectType;
Expand All @@ -512,20 +512,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
} else if (selectType instanceof Type.UnknownType) {
Expand Down Expand Up @@ -603,7 +591,7 @@ public JavaType.Primitive primitive(TypeTag tag) {
((Type.ForAll) methodSymbol.type).qtype :
methodSymbol.type;

List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

Type selectType = methodSymbol.type;
if (selectType instanceof Type.ForAll) {
Expand All @@ -615,20 +603,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ public JavaType.Primitive primitive(TypeTag tag) {

JavaType returnType = null;
List<JavaType> parameterTypes = null;
List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

if (selectType instanceof Type.MethodType) {
Type.MethodType methodType = (Type.MethodType) selectType;
Expand All @@ -520,20 +520,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
} else if (selectType instanceof Type.UnknownType) {
Expand Down Expand Up @@ -590,7 +578,7 @@ public JavaType.Primitive primitive(TypeTag tag) {
} else {
try {
defaultValues = Collections.singletonList(methodSymbol.getDefaultValue().getValue().toString());
} catch(UnsupportedOperationException e) {
} catch (UnsupportedOperationException e) {
// not all Attribute implementations define `getValue()`
}
}
Expand All @@ -611,7 +599,7 @@ public JavaType.Primitive primitive(TypeTag tag) {
((Type.ForAll) methodSymbol.type).qtype :
methodSymbol.type;

List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

Type selectType = methodSymbol.type;
if (selectType instanceof Type.ForAll) {
Expand All @@ -623,20 +611,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ public JavaType.Primitive primitive(TypeTag tag) {

JavaType returnType = null;
List<JavaType> parameterTypes = null;
List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

if (selectType instanceof Type.MethodType) {
Type.MethodType methodType = (Type.MethodType) selectType;
Expand All @@ -531,20 +531,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
} else if (selectType instanceof Type.UnknownType) {
Expand Down Expand Up @@ -622,7 +610,7 @@ public JavaType.Primitive primitive(TypeTag tag) {
((Type.ForAll) methodSymbol.type).qtype :
methodSymbol.type;

List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

Type selectType = methodSymbol.type;
if (selectType instanceof Type.ForAll) {
Expand All @@ -634,20 +622,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ public JavaType.Primitive primitive(TypeTag tag) {

JavaType returnType = null;
List<JavaType> parameterTypes = null;
List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

if (selectType instanceof Type.MethodType) {
Type.MethodType methodType = (Type.MethodType) selectType;
Expand All @@ -514,20 +514,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
} else if (selectType instanceof Type.UnknownType) {
Expand Down Expand Up @@ -604,7 +592,7 @@ public JavaType.Primitive primitive(TypeTag tag) {
((Type.ForAll) methodSymbol.type).qtype :
methodSymbol.type;

List<JavaType.FullyQualified> exceptionTypes = null;
List<JavaType> exceptionTypes = null;

Type selectType = methodSymbol.type;
if (selectType instanceof Type.ForAll) {
Expand All @@ -616,20 +604,8 @@ public JavaType.Primitive primitive(TypeTag tag) {
if (!methodType.thrown.isEmpty()) {
exceptionTypes = new ArrayList<>(methodType.thrown.size());
for (Type exceptionType : methodType.thrown) {
JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType));
if (javaType == null) {
// if the type cannot be resolved to a class (it might not be on the classpath, or it might have
// been mapped to cyclic)
if (exceptionType instanceof Type.ClassType) {
Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym;
javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class,
null, null, null, null, null, null, null);
}
}
if (javaType != null) {
// if the exception type is not resolved, it is not added to the list of exceptions
exceptionTypes.add(javaType);
}
JavaType javaType = type(exceptionType);
exceptionTypes.add(javaType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ default JavaType firstMethodParameter(String methodName) {
return methodType(methodName).getParameterTypes().get(0);
}

@Test
default void declaringTypeRefersToParameterizedClass() {
JavaType.FullyQualified declaringType = methodType("nameShadow").getDeclaringType();
assertThat(declaringType.getTypeParameters())
.describedAs("If it points to the raw class, " +
"method level name shadowing of generic " +
"type variables cannot be detected.")
.isNotEmpty();
}

@Test
default void javaLangObjectHasNoSupertype() {
assertThat(goatType().getSupertype().getSupertype()).isNull();
Expand Down Expand Up @@ -242,4 +252,18 @@ default void recursiveIntersection() {
JavaType.GenericTypeVariable clazz = TypeUtils.asGeneric(firstMethodParameter("recursiveIntersection"));
assertThat(clazz.toString()).isEqualTo("Generic{U extends org.openrewrite.java.JavaTypeGoat$Extension<Generic{U}> & org.openrewrite.java.Intersection<Generic{U}>}");
}

@Test
default void throwsGenericExceptions() {
JavaType.Method method = methodType("throwsGenericException");
JavaType ex = method.getThrownExceptions().get(0);

assertThat(ex).isInstanceOf(JavaType.GenericTypeVariable.class);

JavaType.GenericTypeVariable generic = (JavaType.GenericTypeVariable) ex;
assertThat(generic.getName()).isEqualTo("T");
assertThat(generic.getVariance()).isEqualTo(COVARIANT);
assertThat(TypeUtils.asFullyQualified(generic.getBounds().get(0))
.getFullyQualifiedName()).isEqualTo("java.io.FileNotFoundException");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex
})).afterRecipe(run -> {
J.CompilationUnit cu = (J.CompilationUnit) run.getChangeset().getAllResults().get(0).getAfter();
J.MethodDeclaration testMethodDecl = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0);
assertThat(testMethodDecl.getMethodType().getThrownExceptions().stream().map(JavaType.FullyQualified::getFullyQualifiedName))
assertThat(testMethodDecl.getMethodType().getThrownExceptions().stream()
.map(JavaType.FullyQualified.class::cast)
.map(JavaType.FullyQualified::getFullyQualifiedName))
.containsExactly("java.lang.Exception");
}),
java(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public JavaType visitMethod(JavaType.Method method, P p) {
m = m.withDeclaringType((JavaType.FullyQualified) visit(m.getDeclaringType(), p));
m = m.withReturnType(visit(m.getReturnType(), p));
m = m.withParameterTypes(ListUtils.map(m.getParameterTypes(), pt -> visit(pt, p)));
m = m.withThrownExceptions(ListUtils.map(m.getThrownExceptions(), t -> (JavaType.FullyQualified) visit(t, p)));
m = m.withThrownExceptions(ListUtils.map(m.getThrownExceptions(), t -> visit(t, p)));
m = m.withAnnotations(ListUtils.map(m.getAnnotations(), a -> (JavaType.FullyQualified) visit(a, p)));
return m;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public JavaType visitMethod(JavaType.Method method, P p) {
(JavaType.FullyQualified) visit(method.getDeclaringType(), p),
visit(method.getReturnType(), p),
mapInPlace(method.getParameterTypes().toArray(EMPTY_JAVA_TYPE_ARRAY), pt -> visit(pt, p)),
mapInPlace(method.getThrownExceptions().toArray(EMPTY_FULLY_QUALIFIED_ARRAY), t -> (JavaType.FullyQualified) visit(t, p)),
mapInPlace(method.getThrownExceptions().toArray(EMPTY_JAVA_TYPE_ARRAY), t -> visit(t, p)),
mapInPlace(method.getAnnotations().toArray(EMPTY_FULLY_QUALIFIED_ARRAY), a -> (JavaType.FullyQualified) visit(a, p))
);
}
Expand Down
Loading

0 comments on commit 15740e4

Please sign in to comment.