Home | History | Annotate | Download | only in contexts
      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