Home | History | Annotate | Download | only in symbolsolver
      1 package com.github.javaparser.symbolsolver;
      2 
      3 import com.github.javaparser.ast.CompilationUnit;
      4 import com.github.javaparser.ast.Node;
      5 import com.github.javaparser.ast.body.*;
      6 import com.github.javaparser.ast.expr.Expression;
      7 import com.github.javaparser.ast.expr.MethodCallExpr;
      8 import com.github.javaparser.ast.expr.NameExpr;
      9 import com.github.javaparser.ast.expr.ThisExpr;
     10 import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
     11 import com.github.javaparser.ast.type.Type;
     12 import com.github.javaparser.resolution.SymbolResolver;
     13 import com.github.javaparser.resolution.UnsolvedSymbolException;
     14 import com.github.javaparser.resolution.declarations.*;
     15 import com.github.javaparser.resolution.types.ResolvedType;
     16 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
     17 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
     18 import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*;
     19 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
     20 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
     21 
     22 /**
     23  * This implementation of the SymbolResolver wraps the functionalities of the library to make them easily usable
     24  * from JavaParser nodes.
     25  *
     26  * An instance of this class should be created once and then injected in all the CompilationUnit for which we
     27  * want to enable symbol resolution. To do so the method inject can be used.
     28  *
     29  * @author Federico Tomassetti
     30  */
     31 public class JavaSymbolSolver implements SymbolResolver {
     32 
     33     private TypeSolver typeSolver;
     34 
     35     public JavaSymbolSolver(TypeSolver typeSolver) {
     36         this.typeSolver = typeSolver;
     37     }
     38 
     39     /**
     40      * Register this SymbolResolver into a CompilationUnit, so that symbol resolution becomes available to
     41      * all nodes part of the CompilationUnit.
     42      */
     43     public void inject(CompilationUnit destination) {
     44         destination.setData(Node.SYMBOL_RESOLVER_KEY, this);
     45     }
     46 
     47     @Override
     48     public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
     49         if (node instanceof MethodDeclaration) {
     50             return resultClass.cast(new JavaParserMethodDeclaration((MethodDeclaration)node, typeSolver));
     51         }
     52         if (node instanceof ClassOrInterfaceDeclaration) {
     53             ResolvedReferenceTypeDeclaration resolved = JavaParserFactory.toTypeDeclaration(node, typeSolver);
     54             if (resultClass.isInstance(resolved)) {
     55                 return resultClass.cast(resolved);
     56             }
     57         }
     58         if (node instanceof EnumDeclaration) {
     59             ResolvedReferenceTypeDeclaration resolved = JavaParserFactory.toTypeDeclaration(node, typeSolver);
     60             if (resultClass.isInstance(resolved)) {
     61                 return resultClass.cast(resolved);
     62             }
     63         }
     64         if (node instanceof EnumConstantDeclaration) {
     65             ResolvedEnumDeclaration enumDeclaration = node.findParent(EnumDeclaration.class).get().resolve().asEnum();
     66             ResolvedEnumConstantDeclaration resolved = enumDeclaration.getEnumConstants().stream().filter(c -> ((JavaParserEnumConstantDeclaration)c).getWrappedNode() == node).findFirst().get();
     67             if (resultClass.isInstance(resolved)) {
     68                 return resultClass.cast(resolved);
     69             }
     70         }
     71         if (node instanceof ConstructorDeclaration) {
     72             ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration)node;
     73             ClassOrInterfaceDeclaration classOrInterfaceDeclaration = (ClassOrInterfaceDeclaration)node.getParentNode().get();
     74             ResolvedClassDeclaration resolvedClass = resolveDeclaration(classOrInterfaceDeclaration, ResolvedClassDeclaration.class).asClass();
     75             ResolvedConstructorDeclaration resolved =  resolvedClass.getConstructors().stream().filter(c -> ((JavaParserConstructorDeclaration)c).getWrappedNode() == constructorDeclaration).findFirst().get();
     76             if (resultClass.isInstance(resolved)) {
     77                 return resultClass.cast(resolved);
     78             }
     79         }
     80         if (node instanceof AnnotationDeclaration) {
     81             ResolvedReferenceTypeDeclaration resolved = JavaParserFactory.toTypeDeclaration(node, typeSolver);
     82             if (resultClass.isInstance(resolved)) {
     83                 return resultClass.cast(resolved);
     84             }
     85         }
     86         if (node instanceof AnnotationMemberDeclaration) {
     87             ResolvedAnnotationDeclaration annotationDeclaration = node.findParent(AnnotationDeclaration.class).get().resolve();
     88             ResolvedAnnotationMemberDeclaration resolved = annotationDeclaration.getAnnotationMembers().stream().filter(c -> ((JavaParserAnnotationMemberDeclaration)c).getWrappedNode() == node).findFirst().get();
     89             if (resultClass.isInstance(resolved)) {
     90                 return resultClass.cast(resolved);
     91             }
     92         }
     93         if (node instanceof FieldDeclaration) {
     94             FieldDeclaration fieldDeclaration = (FieldDeclaration)node;
     95             if (fieldDeclaration.getVariables().size() != 1) {
     96                 throw new RuntimeException("Cannot resolve a Field Declaration including multiple variable declarators. Resolve the single variable declarators");
     97             }
     98             ResolvedFieldDeclaration resolved = new JavaParserFieldDeclaration(fieldDeclaration.getVariable(0), typeSolver);
     99             if (resultClass.isInstance(resolved)) {
    100                 return resultClass.cast(resolved);
    101             }
    102         }
    103         if (node instanceof VariableDeclarator) {
    104             ResolvedFieldDeclaration resolved = new JavaParserFieldDeclaration((VariableDeclarator)node, typeSolver);
    105             if (resultClass.isInstance(resolved)) {
    106                 return resultClass.cast(resolved);
    107             }
    108         }
    109         if (node instanceof MethodCallExpr) {
    110             SymbolReference<ResolvedMethodDeclaration> result = JavaParserFacade.get(typeSolver).solve((MethodCallExpr)node);
    111             if (result.isSolved()) {
    112                 if (resultClass.isInstance(result.getCorrespondingDeclaration())) {
    113                     return resultClass.cast(result.getCorrespondingDeclaration());
    114                 }
    115             } else {
    116                 throw new UnsolvedSymbolException("We are unable to find the method declaration corresponding to " + node);
    117             }
    118         }
    119         if (node instanceof NameExpr) {
    120             SymbolReference<? extends ResolvedValueDeclaration> result = JavaParserFacade.get(typeSolver).solve((NameExpr) node);
    121             if (result.isSolved()) {
    122                 if (resultClass.isInstance(result.getCorrespondingDeclaration())) {
    123                     return resultClass.cast(result.getCorrespondingDeclaration());
    124                 }
    125             } else {
    126                 throw new UnsolvedSymbolException("We are unable to find the value declaration corresponding to " + node);
    127             }
    128         }
    129         if (node instanceof ThisExpr) {
    130             SymbolReference<ResolvedTypeDeclaration> result = JavaParserFacade.get(typeSolver).solve((ThisExpr) node);
    131             if (result.isSolved()) {
    132                 if (resultClass.isInstance(result.getCorrespondingDeclaration())) {
    133                     return resultClass.cast(result.getCorrespondingDeclaration());
    134                 }
    135             } else {
    136                 throw new UnsolvedSymbolException("We are unable to find the type declaration corresponding to " + node);
    137             }
    138         }
    139         if (node instanceof ExplicitConstructorInvocationStmt) {
    140             SymbolReference<ResolvedConstructorDeclaration> result = JavaParserFacade.get(typeSolver).solve((ExplicitConstructorInvocationStmt) node);
    141             if (result.isSolved()) {
    142                 if (resultClass.isInstance(result.getCorrespondingDeclaration())) {
    143                     return resultClass.cast(result.getCorrespondingDeclaration());
    144                 }
    145             } else {
    146                 throw new UnsolvedSymbolException("We are unable to find the constructor declaration corresponding to " + node);
    147             }
    148         }
    149         if (node instanceof Parameter) {
    150             if (ResolvedParameterDeclaration.class.equals(resultClass)) {
    151                 Parameter parameter = (Parameter)node;
    152                 CallableDeclaration callableDeclaration = node.findParent(CallableDeclaration.class).get();
    153                 ResolvedMethodLikeDeclaration resolvedMethodLikeDeclaration;
    154                 if (callableDeclaration.isConstructorDeclaration()) {
    155                     resolvedMethodLikeDeclaration = callableDeclaration.asConstructorDeclaration().resolve();
    156                 } else {
    157                     resolvedMethodLikeDeclaration = callableDeclaration.asMethodDeclaration().resolve();
    158                 }
    159                 for (int i=0;i<resolvedMethodLikeDeclaration.getNumberOfParams();i++) {
    160                     if (resolvedMethodLikeDeclaration.getParam(i).getName().equals(parameter.getNameAsString())) {
    161                         return resultClass.cast(resolvedMethodLikeDeclaration.getParam(i));
    162                     }
    163                 }
    164             }
    165         }
    166         throw new UnsupportedOperationException("Unable to find the declaration of type " + resultClass.getSimpleName()
    167                 + " from " + node.getClass().getSimpleName());
    168     }
    169 
    170     @Override
    171     public <T> T toResolvedType(Type javaparserType, Class<T> resultClass) {
    172         ResolvedType resolvedType = JavaParserFacade.get(typeSolver).convertToUsage(javaparserType, javaparserType);
    173         if (resultClass.isInstance(resolvedType)) {
    174             return resultClass.cast(resolvedType);
    175         }
    176         throw new UnsupportedOperationException("Unable to get the resolved type of class "
    177                 + resultClass.getSimpleName() + " from " + javaparserType);
    178     }
    179 
    180     @Override
    181     public ResolvedType calculateType(Expression expression) {
    182         return JavaParserFacade.get(typeSolver).getType(expression);
    183     }
    184 }
    185