1package com.github.javaparser.symbolsolver; 2 3import com.github.javaparser.ast.CompilationUnit; 4import com.github.javaparser.ast.Node; 5import com.github.javaparser.ast.body.*; 6import com.github.javaparser.ast.expr.Expression; 7import com.github.javaparser.ast.expr.MethodCallExpr; 8import com.github.javaparser.ast.expr.NameExpr; 9import com.github.javaparser.ast.expr.ThisExpr; 10import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; 11import com.github.javaparser.ast.type.Type; 12import com.github.javaparser.resolution.SymbolResolver; 13import com.github.javaparser.resolution.UnsolvedSymbolException; 14import com.github.javaparser.resolution.declarations.*; 15import com.github.javaparser.resolution.types.ResolvedType; 16import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 17import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; 18import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*; 19import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 20import 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 */ 31public 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