diff options
Diffstat (limited to 'javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java')
-rw-r--r-- | javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java new file mode 100644 index 000000000..993f42d29 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java @@ -0,0 +1,133 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.contexts; + +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters; +import com.github.javaparser.ast.type.TypeParameter; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.reflectionmodel.*; +import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic; +import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserTypeDeclarationAdapter { + + private com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode; + private TypeSolver typeSolver; + private Context context; + private ResolvedReferenceTypeDeclaration typeDeclaration; + + public JavaParserTypeDeclarationAdapter(com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode, TypeSolver typeSolver, + ResolvedReferenceTypeDeclaration typeDeclaration, + Context context) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + this.typeDeclaration = typeDeclaration; + this.context = context; + } + + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (this.wrappedNode.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(wrappedNode)); + } + + // Internal classes + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + com.github.javaparser.ast.body.TypeDeclaration<?> internalType = (com.github.javaparser.ast.body.TypeDeclaration<?>) member; + if (internalType.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(internalType)); + } else if (name.startsWith(String.format("%s.%s", wrappedNode.getName(), internalType.getName()))) { + return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(wrappedNode.getName().getId().length() + 1), typeSolver); + } else if (name.startsWith(String.format("%s.", internalType.getName()))) { + return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(internalType.getName().getId().length() + 1), typeSolver); + } + } + } + + if (wrappedNode instanceof NodeWithTypeParameters) { + NodeWithTypeParameters<?> nodeWithTypeParameters = (NodeWithTypeParameters<?>) wrappedNode; + for (TypeParameter astTpRaw : nodeWithTypeParameters.getTypeParameters()) { + TypeParameter astTp = astTpRaw; + if (astTp.getName().getId().equals(name)) { + return SymbolReference.solved(new JavaParserTypeParameter(astTp, typeSolver)); + } + } + } + + // Look into extended classes and implemented interfaces + for (ResolvedReferenceType ancestor : this.typeDeclaration.getAncestors()) { + try { + for (ResolvedTypeDeclaration internalTypeDeclaration : ancestor.getTypeDeclaration().internalTypes()) { + if (internalTypeDeclaration.getName().equals(name)) { + return SymbolReference.solved(internalTypeDeclaration); + } + } + } catch (UnsupportedOperationException e) { + // just continue using the next ancestor + } + } + + return context.getParent().solveType(name, typeSolver); + } + + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + List<ResolvedMethodDeclaration> candidateMethods = typeDeclaration.getDeclaredMethods().stream() + .filter(m -> m.getName().equals(name)) + .filter(m -> !staticOnly || (staticOnly && m.isStatic())) + .collect(Collectors.toList()); + // We want to avoid infinite recursion in case of Object having Object as ancestor + if (!Object.class.getCanonicalName().equals(typeDeclaration.getQualifiedName())) { + for (ResolvedReferenceType ancestor : typeDeclaration.getAncestors()) { + // Avoid recursion on self + if (typeDeclaration != ancestor.getTypeDeclaration()) { + SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic + .solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver); + // consider methods from superclasses and only default methods from interfaces : + // not true, we should keep abstract as a valid candidate + // abstract are removed in MethodResolutionLogic.isApplicable is necessary + if (res.isSolved()) { + candidateMethods.add(res.getCorrespondingDeclaration()); + } + } + } + } + // We want to avoid infinite recursion when a class is using its own method + // see issue #75 + if (candidateMethods.isEmpty()) { + SymbolReference<ResolvedMethodDeclaration> parentSolution = context.getParent().solveMethod(name, argumentsTypes, staticOnly, typeSolver); + if (parentSolution.isSolved()) { + candidateMethods.add(parentSolution.getCorrespondingDeclaration()); + } + } + + // if is interface and candidate method list is empty, we should check the Object Methods + if (candidateMethods.isEmpty() && typeDeclaration.isInterface()) { + SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver); + if (res.isSolved()) { + candidateMethods.add(res.getCorrespondingDeclaration()); + } + } + + return MethodResolutionLogic.findMostApplicable(candidateMethods, name, argumentsTypes, typeSolver); + } + + public SymbolReference<ResolvedConstructorDeclaration> solveConstructor(List<ResolvedType> argumentsTypes, TypeSolver typeSolver) { + if (typeDeclaration instanceof ResolvedClassDeclaration) { + return ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) typeDeclaration).getConstructors(), argumentsTypes, typeSolver); + } + return SymbolReference.unsolved(ResolvedConstructorDeclaration.class); + } +} |