| 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); |
| } |
| } |