1 package com.github.javaparser.symbolsolver.javaparsermodel.contexts; 2 3 import com.github.javaparser.ast.body.BodyDeclaration; 4 import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters; 5 import com.github.javaparser.ast.type.TypeParameter; 6 import com.github.javaparser.resolution.declarations.*; 7 import com.github.javaparser.resolution.types.ResolvedReferenceType; 8 import com.github.javaparser.resolution.types.ResolvedType; 9 import com.github.javaparser.symbolsolver.core.resolution.Context; 10 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 11 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; 12 import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; 13 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 14 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 15 import com.github.javaparser.symbolsolver.reflectionmodel.*; 16 import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic; 17 import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; 18 19 import java.util.List; 20 import java.util.stream.Collectors; 21 22 /** 23 * @author Federico Tomassetti 24 */ 25 public class JavaParserTypeDeclarationAdapter { 26 27 private com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode; 28 private TypeSolver typeSolver; 29 private Context context; 30 private ResolvedReferenceTypeDeclaration typeDeclaration; 31 32 public JavaParserTypeDeclarationAdapter(com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode, TypeSolver typeSolver, 33 ResolvedReferenceTypeDeclaration typeDeclaration, 34 Context context) { 35 this.wrappedNode = wrappedNode; 36 this.typeSolver = typeSolver; 37 this.typeDeclaration = typeDeclaration; 38 this.context = context; 39 } 40 41 public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { 42 if (this.wrappedNode.getName().getId().equals(name)) { 43 return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(wrappedNode)); 44 } 45 46 // Internal classes 47 for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { 48 if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { 49 com.github.javaparser.ast.body.TypeDeclaration<?> internalType = (com.github.javaparser.ast.body.TypeDeclaration<?>) member; 50 if (internalType.getName().getId().equals(name)) { 51 return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(internalType)); 52 } else if (name.startsWith(String.format("%s.%s", wrappedNode.getName(), internalType.getName()))) { 53 return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(wrappedNode.getName().getId().length() + 1), typeSolver); 54 } else if (name.startsWith(String.format("%s.", internalType.getName()))) { 55 return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(internalType.getName().getId().length() + 1), typeSolver); 56 } 57 } 58 } 59 60 if (wrappedNode instanceof NodeWithTypeParameters) { 61 NodeWithTypeParameters<?> nodeWithTypeParameters = (NodeWithTypeParameters<?>) wrappedNode; 62 for (TypeParameter astTpRaw : nodeWithTypeParameters.getTypeParameters()) { 63 TypeParameter astTp = astTpRaw; 64 if (astTp.getName().getId().equals(name)) { 65 return SymbolReference.solved(new JavaParserTypeParameter(astTp, typeSolver)); 66 } 67 } 68 } 69 70 // Look into extended classes and implemented interfaces 71 for (ResolvedReferenceType ancestor : this.typeDeclaration.getAncestors()) { 72 try { 73 for (ResolvedTypeDeclaration internalTypeDeclaration : ancestor.getTypeDeclaration().internalTypes()) { 74 if (internalTypeDeclaration.getName().equals(name)) { 75 return SymbolReference.solved(internalTypeDeclaration); 76 } 77 } 78 } catch (UnsupportedOperationException e) { 79 // just continue using the next ancestor 80 } 81 } 82 83 return context.getParent().solveType(name, typeSolver); 84 } 85 86 public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { 87 List<ResolvedMethodDeclaration> candidateMethods = typeDeclaration.getDeclaredMethods().stream() 88 .filter(m -> m.getName().equals(name)) 89 .filter(m -> !staticOnly || (staticOnly && m.isStatic())) 90 .collect(Collectors.toList()); 91 // We want to avoid infinite recursion in case of Object having Object as ancestor 92 if (!Object.class.getCanonicalName().equals(typeDeclaration.getQualifiedName())) { 93 for (ResolvedReferenceType ancestor : typeDeclaration.getAncestors()) { 94 // Avoid recursion on self 95 if (typeDeclaration != ancestor.getTypeDeclaration()) { 96 SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic 97 .solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver); 98 // consider methods from superclasses and only default methods from interfaces : 99 // not true, we should keep abstract as a valid candidate 100 // abstract are removed in MethodResolutionLogic.isApplicable is necessary 101 if (res.isSolved()) { 102 candidateMethods.add(res.getCorrespondingDeclaration()); 103 } 104 } 105 } 106 } 107 // We want to avoid infinite recursion when a class is using its own method 108 // see issue #75 109 if (candidateMethods.isEmpty()) { 110 SymbolReference<ResolvedMethodDeclaration> parentSolution = context.getParent().solveMethod(name, argumentsTypes, staticOnly, typeSolver); 111 if (parentSolution.isSolved()) { 112 candidateMethods.add(parentSolution.getCorrespondingDeclaration()); 113 } 114 } 115 116 // if is interface and candidate method list is empty, we should check the Object Methods 117 if (candidateMethods.isEmpty() && typeDeclaration.isInterface()) { 118 SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver); 119 if (res.isSolved()) { 120 candidateMethods.add(res.getCorrespondingDeclaration()); 121 } 122 } 123 124 return MethodResolutionLogic.findMostApplicable(candidateMethods, name, argumentsTypes, typeSolver); 125 } 126 127 public SymbolReference<ResolvedConstructorDeclaration> solveConstructor(List<ResolvedType> argumentsTypes, TypeSolver typeSolver) { 128 if (typeDeclaration instanceof ResolvedClassDeclaration) { 129 return ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) typeDeclaration).getConstructors(), argumentsTypes, typeSolver); 130 } 131 return SymbolReference.unsolved(ResolvedConstructorDeclaration.class); 132 } 133 } 134