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