From 8ddfe4661ccc9cb889cceb947ce4de46ac21448f Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Wed, 26 Oct 2016 17:07:37 +0200 Subject: [PATCH] improve how javassist handle generics --- .../JavassistClassDeclaration.java | 41 +++++++++++--- .../JavassistMethodDeclaration.java | 50 +---------------- .../javassistmodel/JavassistUtils.java | 54 +++++++++++++++++-- .../JavassistClassDeclarationTest.java | 42 +++++++++------ .../model/declarations/TypeDeclaration.java | 2 +- 5 files changed, 113 insertions(+), 76 deletions(-) diff --git a/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclaration.java b/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclaration.java index 35d1bdac2b..b1e32c6ce6 100644 --- a/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclaration.java +++ b/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclaration.java @@ -278,26 +278,42 @@ public boolean isClass() { } @Override - public ReferenceTypeImpl getSuperClass() { + public ReferenceType getSuperClass() { try { if (ctClass.getSuperclass() == null) { return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver); } - return new ReferenceTypeImpl(new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver).asClass(), typeSolver); + if (ctClass.getGenericSignature() == null) { + return new ReferenceTypeImpl(new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver), typeSolver); + } + + SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature()); + return JavassistUtils.signatureTypeToType(classSignature.getSuperClass(), typeSolver, this).asReferenceType(); } catch (NotFoundException e) { throw new RuntimeException(e); + } catch (BadBytecode e) { + throw new RuntimeException(e); } } @Override public List getInterfaces() { try { - return Arrays.stream(ctClass.getInterfaces()) - .map(i -> new JavassistInterfaceDeclaration(i, typeSolver)) - .map(i -> new ReferenceTypeImpl(i, typeSolver)) - .collect(Collectors.toList()); + if (ctClass.getGenericSignature() == null) { + return Arrays.stream(ctClass.getInterfaces()) + .map(i -> new JavassistInterfaceDeclaration(i, typeSolver)) + .map(i -> new ReferenceTypeImpl(i, typeSolver)) + .collect(Collectors.toList()); + } else { + SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature()); + return Arrays.stream(classSignature.getInterfaces()) + .map(i -> JavassistUtils.signatureTypeToType(i, typeSolver, this).asReferenceType()) + .collect(Collectors.toList()); + } } catch (NotFoundException e) { throw new RuntimeException(e); + } catch (BadBytecode e) { + throw new RuntimeException(e); } } @@ -335,4 +351,17 @@ public AccessLevel accessLevel() { public List getConstructors() { throw new UnsupportedOperationException(); } + + @Override + public Optional containerType() { + try { + if (ctClass.getDeclaringClass() == null) { + return Optional.empty(); + } else { + throw new UnsupportedOperationException(); + } + } catch (NotFoundException e) { + throw new RuntimeException(e); + } + } } diff --git a/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistMethodDeclaration.java b/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistMethodDeclaration.java index 19404c8e19..10a98d0b99 100644 --- a/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistMethodDeclaration.java +++ b/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistMethodDeclaration.java @@ -19,12 +19,9 @@ import com.github.javaparser.ast.Node; import com.github.javaparser.symbolsolver.core.resolution.Context; import com.github.javaparser.symbolsolver.model.declarations.*; -import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.methods.MethodUsage; -import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.typesystem.Type; -import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable; -import com.github.javaparser.symbolsolver.model.typesystem.Wildcard; import javassist.CtMethod; import javassist.NotFoundException; import javassist.bytecode.BadBytecode; @@ -34,7 +31,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; public class JavassistMethodDeclaration implements MethodDeclaration { @@ -116,7 +112,7 @@ public ParameterDeclaration getParam(int i) { if (ctMethod.getGenericSignature() != null) { SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctMethod.getGenericSignature()); SignatureAttribute.Type signatureType = methodSignature.getParameterTypes()[i]; - return new JavassistParameterDeclaration(signatureTypeToType(signatureType), typeSolver, variadic); + return new JavassistParameterDeclaration(JavassistUtils.signatureTypeToType(signatureType, typeSolver, this), typeSolver, variadic); } else { return new JavassistParameterDeclaration(ctMethod.getParameterTypes()[0], typeSolver, variadic); } @@ -127,48 +123,6 @@ public ParameterDeclaration getParam(int i) { } } - private Type signatureTypeToType(SignatureAttribute.Type signatureType){ - if (signatureType instanceof SignatureAttribute.ClassType) { - SignatureAttribute.ClassType classType = (SignatureAttribute.ClassType)signatureType; - List typeParameters = Arrays.stream(classType.getTypeArguments()).map(ta -> typeArgumentToType(ta)).collect(Collectors.toList()); - TypeDeclaration typeDeclaration = typeSolver.solveType(classType.getName()); - return new ReferenceTypeImpl(typeDeclaration, typeParameters, typeSolver); - } else { - throw new RuntimeException(signatureType.getClass().getCanonicalName()); - } - } - - private Type objectTypeArgumentToType(SignatureAttribute.ObjectType typeArgument){ - String typeName = typeArgument.jvmTypeName(); - Optional type = getGenericParameterByName(typeName); - if (type.isPresent()) { - return type.get(); - } else { - throw new UnsupportedOperationException(typeName); - } - } - - private Optional getGenericParameterByName(String typeName) { - Optional tp = findTypeParameter(typeName); - return tp.map(it -> new TypeVariable(it)); - } - - private Type typeArgumentToType(SignatureAttribute.TypeArgument typeArgument){ - if (typeArgument.isWildcard()) { - if (typeArgument.getType() == null) { - return Wildcard.UNBOUNDED; - } else if (typeArgument.getKind() == '+'){ - return Wildcard.extendsBound(objectTypeArgumentToType(typeArgument.getType())); - } else if (typeArgument.getKind() == '-'){ - return Wildcard.superBound(objectTypeArgumentToType(typeArgument.getType())); - } else { - throw new UnsupportedOperationException(); - } - } else { - throw new UnsupportedOperationException(); - } - } - public MethodUsage getUsage(Node node) { throw new UnsupportedOperationException(); } diff --git a/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistUtils.java b/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistUtils.java index 52e3c5a088..762b004c2f 100644 --- a/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistUtils.java +++ b/java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistUtils.java @@ -18,9 +18,15 @@ import com.github.javaparser.symbolsolver.core.resolution.Context; import com.github.javaparser.symbolsolver.javassistmodel.contexts.JavassistMethodContext; +import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration; +import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration; +import com.github.javaparser.symbolsolver.model.declarations.TypeParametrizable; import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.methods.MethodUsage; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; import com.github.javaparser.symbolsolver.model.typesystem.Type; +import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable; +import com.github.javaparser.symbolsolver.model.typesystem.Wildcard; import com.github.javaparser.symbolsolver.resolution.SymbolSolver; import javassist.CtClass; import javassist.CtMethod; @@ -28,10 +34,8 @@ import javassist.bytecode.BadBytecode; import javassist.bytecode.SignatureAttribute; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; /** * @author Federico Tomassetti @@ -110,4 +114,46 @@ private static List parseTypeParameters(String signature, TypeSolver typeS return Collections.emptyList(); } } + + static Type signatureTypeToType(SignatureAttribute.Type signatureType, TypeSolver typeSolver, TypeParametrizable typeParametrizable){ + if (signatureType instanceof SignatureAttribute.ClassType) { + SignatureAttribute.ClassType classType = (SignatureAttribute.ClassType)signatureType; + List typeParameters = classType.getTypeArguments() == null ? Collections.emptyList() : Arrays.stream(classType.getTypeArguments()).map(ta -> typeArgumentToType(ta, typeSolver, typeParametrizable)).collect(Collectors.toList()); + TypeDeclaration typeDeclaration = typeSolver.solveType(classType.getName()); + return new ReferenceTypeImpl(typeDeclaration, typeParameters, typeSolver); + } else { + throw new RuntimeException(signatureType.getClass().getCanonicalName()); + } + } + + private static Type objectTypeArgumentToType(SignatureAttribute.ObjectType typeArgument, TypeSolver typeSolver, TypeParametrizable typeParametrizable){ + String typeName = typeArgument.jvmTypeName(); + Optional type = getGenericParameterByName(typeName, typeParametrizable); + if (type.isPresent()) { + return type.get(); + } else { + return new ReferenceTypeImpl(typeSolver.solveType(typeName), typeSolver); + } + } + + private static Optional getGenericParameterByName(String typeName, TypeParametrizable typeParametrizable) { + Optional tp = typeParametrizable.findTypeParameter(typeName); + return tp.map(it -> new TypeVariable(it)); + } + + private static Type typeArgumentToType(SignatureAttribute.TypeArgument typeArgument, TypeSolver typeSolver, TypeParametrizable typeParametrizable){ + if (typeArgument.isWildcard()) { + if (typeArgument.getType() == null) { + return Wildcard.UNBOUNDED; + } else if (typeArgument.getKind() == '+') { + return Wildcard.extendsBound(objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable)); + } else if (typeArgument.getKind() == '-') { + return Wildcard.superBound(objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable)); + } else { + throw new UnsupportedOperationException(); + } + } else { + return objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable); + } + } } diff --git a/java-symbol-solver-core/src/test/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclarationTest.java b/java-symbol-solver-core/src/test/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclarationTest.java index a79b6f2b1e..8441b7e283 100644 --- a/java-symbol-solver-core/src/test/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclarationTest.java +++ b/java-symbol-solver-core/src/test/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistClassDeclarationTest.java @@ -120,6 +120,19 @@ public void testGetSuperclass() { assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName()); } + @Test + public void testGetSuperclassWithoutTypeParameters() { + JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); + assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName()); + } + + @Test + public void testGetSuperclassWithTypeParameters() { + JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ConstructorDeclaration"); + assertEquals("com.github.javaparser.ast.body.BodyDeclaration", compilationUnit.getSuperClass().getQualifiedName()); + assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", compilationUnit.getSuperClass().typeParametersMap().getValueBySignature("com.github.javaparser.ast.body.BodyDeclaration.T").get().asReferenceType().getQualifiedName()); + } + @Test public void testGetAllSuperclasses() { JavassistClassDeclaration cu = (JavassistClassDeclaration) typeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); @@ -150,19 +163,6 @@ public void testGetAllInterfaces() { assertEquals(ImmutableSet.of("com.github.javaparser.ast.NamedNode", "com.github.javaparser.ast.body.AnnotableNode", "com.github.javaparser.ast.DocumentableNode"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); } - @Test - public void testGetSuperclassWithoutTypeParameters() { - JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); - assertEquals("com.github.javaparser.ast.Node", compilationUnit.getSuperClass().getQualifiedName()); - } - - @Test - public void testGetSuperclassWithTypeParameters() { - JavassistClassDeclaration compilationUnit = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ConstructorDeclaration"); - assertEquals("com.github.javaparser.ast.body.BodyDeclaration", compilationUnit.getSuperClass().getQualifiedName()); - assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", compilationUnit.getSuperClass().typeParametersMap().getValueBySignature("com.github.javaparser.ast.body.BodyDeclaration.T").get().asReferenceType().getQualifiedName()); - } - @Test public void testGetAllSuperclassesWithoutTypeParameters() { JavassistClassDeclaration cu = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); @@ -196,7 +196,7 @@ public void testGetInterfacesWithoutParameters() { assertEquals(ImmutableSet.of(), compilationUnit.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); JavassistClassDeclaration coid = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ClassOrInterfaceDeclaration"); - assertEquals(ImmutableSet.of("com.github.javaparser.ast.DocumentableNode"), coid.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); + assertEquals(ImmutableSet.of("com.github.javaparser.ast.nodeTypes.NodeWithExtends", "com.github.javaparser.ast.nodeTypes.NodeWithImplements"), coid.getInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); } @Test @@ -240,7 +240,14 @@ public void testGetAllInterfacesWithoutParameters() { assertEquals(ImmutableSet.of("java.lang.Cloneable"), compilationUnit.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); JavassistClassDeclaration coid = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.body.ClassOrInterfaceDeclaration"); - assertEquals(ImmutableSet.of("java.lang.Cloneable", "com.github.javaparser.ast.NamedNode", "com.github.javaparser.ast.body.AnnotableNode", "com.github.javaparser.ast.DocumentableNode"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); + assertEquals(ImmutableSet.of("com.github.javaparser.ast.nodeTypes.NodeWithExtends", + "com.github.javaparser.ast.nodeTypes.NodeWithAnnotations", + "java.lang.Cloneable", + "com.github.javaparser.ast.nodeTypes.NodeWithImplements", + "com.github.javaparser.ast.nodeTypes.NodeWithName", + "com.github.javaparser.ast.nodeTypes.NodeWithModifiers", + "com.github.javaparser.ast.nodeTypes.NodeWithJavaDoc", + "com.github.javaparser.ast.nodeTypes.NodeWithMembers"), coid.getAllInterfaces().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); } @Test @@ -326,7 +333,7 @@ public void testGetAncestorsWithTypeParameters() { @Test public void testGetAllAncestorsWithoutTypeParameters() { - JavassistClassDeclaration cu = (JavassistClassDeclaration) typeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); + JavassistClassDeclaration cu = (JavassistClassDeclaration) newTypeSolver.solveType("com.github.javaparser.ast.CompilationUnit"); assertEquals(ImmutableSet.of("java.lang.Cloneable", "com.github.javaparser.ast.Node", "java.lang.Object"), cu.getAllAncestors().stream().map(i -> i.getQualifiedName()).collect(Collectors.toSet())); } @@ -380,5 +387,6 @@ public void testGetAllAncestorsWithTypeParameters() { ancestor = constructorDeclaration.getAllAncestors().get(11); assertEquals("com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt", ancestor.getQualifiedName()); assertEquals("com.github.javaparser.ast.body.ConstructorDeclaration", ancestor.typeParametersMap().getValueBySignature("com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt.T").get().asReferenceType().getQualifiedName()); - } + } + } diff --git a/java-symbol-solver-model/src/main/java/com/github/javaparser/symbolsolver/model/declarations/TypeDeclaration.java b/java-symbol-solver-model/src/main/java/com/github/javaparser/symbolsolver/model/declarations/TypeDeclaration.java index 17608bf421..ecd76da977 100644 --- a/java-symbol-solver-model/src/main/java/com/github/javaparser/symbolsolver/model/declarations/TypeDeclaration.java +++ b/java-symbol-solver-model/src/main/java/com/github/javaparser/symbolsolver/model/declarations/TypeDeclaration.java @@ -50,7 +50,7 @@ default Set internalTypes() { * @return */ default Optional containerType() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("containerType is not supported for " + this.getClass().getCanonicalName()); } ///