1 /* 2 * Copyright 2016 Federico Tomassetti 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.github.javaparser.symbolsolver.javaparsermodel; 18 19 import com.github.javaparser.ast.CompilationUnit; 20 import com.github.javaparser.ast.Node; 21 import com.github.javaparser.ast.NodeList; 22 import com.github.javaparser.ast.body.*; 23 import com.github.javaparser.ast.body.EnumDeclaration; 24 import com.github.javaparser.ast.expr.*; 25 import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; 26 import com.github.javaparser.ast.type.*; 27 import com.github.javaparser.resolution.MethodUsage; 28 import com.github.javaparser.resolution.UnsolvedSymbolException; 29 import com.github.javaparser.resolution.declarations.*; 30 import com.github.javaparser.resolution.types.*; 31 import com.github.javaparser.symbolsolver.core.resolution.Context; 32 import com.github.javaparser.symbolsolver.javaparsermodel.contexts.FieldAccessContext; 33 import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*; 34 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 35 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 36 import com.github.javaparser.symbolsolver.model.typesystem.*; 37 import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; 38 import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic; 39 import com.github.javaparser.symbolsolver.resolution.SymbolSolver; 40 41 import java.util.*; 42 import java.util.logging.ConsoleHandler; 43 import java.util.logging.Level; 44 import java.util.logging.Logger; 45 import java.util.stream.Collectors; 46 47 import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; 48 49 /** 50 * Class to be used by final users to solve symbols for JavaParser ASTs. 51 * 52 * @author Federico Tomassetti 53 */ 54 public class JavaParserFacade { 55 56 private static Logger logger = Logger.getLogger(JavaParserFacade.class.getCanonicalName()); 57 58 static { 59 logger.setLevel(Level.INFO); 60 ConsoleHandler consoleHandler = new ConsoleHandler(); 61 consoleHandler.setLevel(Level.INFO); 62 logger.addHandler(consoleHandler); 63 } 64 65 private static Map<TypeSolver, JavaParserFacade> instances = new WeakHashMap<>(); 66 private TypeSolver typeSolver; 67 private SymbolSolver symbolSolver; 68 private Map<Node, ResolvedType> cacheWithLambdasSolved = new IdentityHashMap<>(); 69 private Map<Node, ResolvedType> cacheWithoutLambdasSolved = new IdentityHashMap<>(); 70 private TypeExtractor typeExtractor; 71 72 private JavaParserFacade(TypeSolver typeSolver) { 73 this.typeSolver = typeSolver.getRoot(); 74 this.symbolSolver = new SymbolSolver(typeSolver); 75 this.typeExtractor = new TypeExtractor(typeSolver, this); 76 } 77 78 public TypeSolver getTypeSolver() { 79 return typeSolver; 80 } 81 82 public SymbolSolver getSymbolSolver() { 83 return symbolSolver; 84 } 85 86 public static JavaParserFacade get(TypeSolver typeSolver) { 87 return instances.computeIfAbsent(typeSolver, JavaParserFacade::new); 88 } 89 90 /** 91 * This method is used to clear internal caches for the sake of releasing memory. 92 */ 93 public static void clearInstances() { 94 instances.clear(); 95 } 96 97 protected static ResolvedType solveGenericTypes(ResolvedType type, Context context, TypeSolver typeSolver) { 98 if (type.isTypeVariable()) { 99 return context.solveGenericType(type.describe(), typeSolver).orElse(type); 100 } 101 if (type.isWildcard()) { 102 if (type.asWildcard().isExtends() || type.asWildcard().isSuper()) { 103 ResolvedWildcard wildcardUsage = type.asWildcard(); 104 ResolvedType boundResolved = solveGenericTypes(wildcardUsage.getBoundedType(), context, typeSolver); 105 if (wildcardUsage.isExtends()) { 106 return ResolvedWildcard.extendsBound(boundResolved); 107 } else { 108 return ResolvedWildcard.superBound(boundResolved); 109 } 110 } 111 } 112 return type; 113 } 114 115 public SymbolReference<? extends ResolvedValueDeclaration> solve(NameExpr nameExpr) { 116 return symbolSolver.solveSymbol(nameExpr.getName().getId(), nameExpr); 117 } 118 119 public SymbolReference<? extends ResolvedValueDeclaration> solve(SimpleName nameExpr) { 120 return symbolSolver.solveSymbol(nameExpr.getId(), nameExpr); 121 } 122 123 public SymbolReference<? extends ResolvedValueDeclaration> solve(Expression expr) { 124 return expr.toNameExpr().map(this::solve).orElseThrow(() -> new IllegalArgumentException(expr.getClass().getCanonicalName())); 125 } 126 127 public SymbolReference<ResolvedMethodDeclaration> solve(MethodCallExpr methodCallExpr) { 128 return solve(methodCallExpr, true); 129 } 130 131 public SymbolReference<ResolvedConstructorDeclaration> solve(ObjectCreationExpr objectCreationExpr) { 132 return solve(objectCreationExpr, true); 133 } 134 135 public SymbolReference<ResolvedConstructorDeclaration> solve(ExplicitConstructorInvocationStmt explicitConstructorInvocationStmt) { 136 return solve(explicitConstructorInvocationStmt, true); 137 } 138 139 public SymbolReference<ResolvedConstructorDeclaration> solve(ExplicitConstructorInvocationStmt explicitConstructorInvocationStmt, boolean solveLambdas) { 140 List<ResolvedType> argumentTypes = new LinkedList<>(); 141 List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>(); 142 143 solveArguments(explicitConstructorInvocationStmt, explicitConstructorInvocationStmt.getArguments(), solveLambdas, argumentTypes, placeholders); 144 145 Optional<ClassOrInterfaceDeclaration> optAncestor = explicitConstructorInvocationStmt.getAncestorOfType(ClassOrInterfaceDeclaration.class); 146 if (!optAncestor.isPresent()) { 147 return SymbolReference.unsolved(ResolvedConstructorDeclaration.class); 148 } 149 ClassOrInterfaceDeclaration classNode = optAncestor.get(); 150 ResolvedTypeDeclaration typeDecl = null; 151 if (!explicitConstructorInvocationStmt.isThis()) { 152 ResolvedType classDecl = JavaParserFacade.get(typeSolver).convert(classNode.getExtendedTypes(0), classNode); 153 if (classDecl.isReferenceType()) { 154 typeDecl = classDecl.asReferenceType().getTypeDeclaration(); 155 } 156 } else { 157 SymbolReference<ResolvedTypeDeclaration> sr = JavaParserFactory.getContext(classNode, typeSolver).solveType(classNode.getNameAsString(), typeSolver); 158 if (sr.isSolved()) { 159 typeDecl = sr.getCorrespondingDeclaration(); 160 } 161 } 162 if (typeDecl == null) { 163 return SymbolReference.unsolved(ResolvedConstructorDeclaration.class); 164 } 165 SymbolReference<ResolvedConstructorDeclaration> res = ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) typeDecl).getConstructors(), argumentTypes, typeSolver); 166 for (LambdaArgumentTypePlaceholder placeholder : placeholders) { 167 placeholder.setMethod(res); 168 } 169 return res; 170 } 171 172 public SymbolReference<ResolvedTypeDeclaration> solve(ThisExpr node) { 173 // If 'this' is prefixed by a class eg. MyClass.this 174 if (node.getClassExpr().isPresent()) { 175 // Get the class name 176 String className = node.getClassExpr().get().toString(); 177 // Attempt to resolve using a typeSolver 178 SymbolReference<ResolvedReferenceTypeDeclaration> clazz = typeSolver.tryToSolveType(className); 179 if (clazz.isSolved()) { 180 return SymbolReference.solved(clazz.getCorrespondingDeclaration()); 181 } 182 // Attempt to resolve locally in Compilation unit 183 Optional<CompilationUnit> cu = node.getAncestorOfType(CompilationUnit.class); 184 if (cu.isPresent()) { 185 Optional<ClassOrInterfaceDeclaration> classByName = cu.get().getClassByName(className); 186 if (classByName.isPresent()) { 187 return SymbolReference.solved(getTypeDeclaration(classByName.get())); 188 } 189 } 190 } 191 return SymbolReference.solved(getTypeDeclaration(findContainingTypeDeclOrObjectCreationExpr(node))); 192 } 193 194 /** 195 * Given a constructor call find out to which constructor declaration it corresponds. 196 */ 197 public SymbolReference<ResolvedConstructorDeclaration> solve(ObjectCreationExpr objectCreationExpr, boolean solveLambdas) { 198 List<ResolvedType> argumentTypes = new LinkedList<>(); 199 List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>(); 200 201 solveArguments(objectCreationExpr, objectCreationExpr.getArguments(), solveLambdas, argumentTypes, placeholders); 202 203 ResolvedType classDecl = JavaParserFacade.get(typeSolver).convert(objectCreationExpr.getType(), objectCreationExpr); 204 if (!classDecl.isReferenceType()) { 205 return SymbolReference.unsolved(ResolvedConstructorDeclaration.class); 206 } 207 SymbolReference<ResolvedConstructorDeclaration> res = ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) classDecl.asReferenceType().getTypeDeclaration()).getConstructors(), argumentTypes, typeSolver); 208 for (LambdaArgumentTypePlaceholder placeholder : placeholders) { 209 placeholder.setMethod(res); 210 } 211 return res; 212 } 213 214 private void solveArguments(Node node, NodeList<Expression> args, boolean solveLambdas, List<ResolvedType> argumentTypes, 215 List<LambdaArgumentTypePlaceholder> placeholders) { 216 int i = 0; 217 for (Expression parameterValue : args) { 218 if (parameterValue instanceof LambdaExpr || parameterValue instanceof MethodReferenceExpr) { 219 LambdaArgumentTypePlaceholder placeholder = new LambdaArgumentTypePlaceholder(i); 220 argumentTypes.add(placeholder); 221 placeholders.add(placeholder); 222 } else { 223 try { 224 argumentTypes.add(JavaParserFacade.get(typeSolver).getType(parameterValue, solveLambdas)); 225 } catch (com.github.javaparser.resolution.UnsolvedSymbolException e) { 226 throw e; 227 } catch (Exception e) { 228 throw new RuntimeException(String.format("Unable to calculate the type of a parameter of a method call. Method call: %s, Parameter: %s", 229 node, parameterValue), e); 230 } 231 } 232 i++; 233 } 234 } 235 236 /** 237 * Given a method call find out to which method declaration it corresponds. 238 */ 239 public SymbolReference<ResolvedMethodDeclaration> solve(MethodCallExpr methodCallExpr, boolean solveLambdas) { 240 List<ResolvedType> argumentTypes = new LinkedList<>(); 241 List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>(); 242 243 solveArguments(methodCallExpr, methodCallExpr.getArguments(), solveLambdas, argumentTypes, placeholders); 244 245 SymbolReference<ResolvedMethodDeclaration> res = JavaParserFactory.getContext(methodCallExpr, typeSolver).solveMethod(methodCallExpr.getName().getId(), argumentTypes, false, typeSolver); 246 for (LambdaArgumentTypePlaceholder placeholder : placeholders) { 247 placeholder.setMethod(res); 248 } 249 return res; 250 } 251 252 public SymbolReference<ResolvedAnnotationDeclaration> solve(AnnotationExpr annotationExpr) { 253 Context context = JavaParserFactory.getContext(annotationExpr, typeSolver); 254 SymbolReference<ResolvedTypeDeclaration> typeDeclarationSymbolReference = context.solveType(annotationExpr.getNameAsString(), typeSolver); 255 ResolvedAnnotationDeclaration annotationDeclaration = (ResolvedAnnotationDeclaration) typeDeclarationSymbolReference.getCorrespondingDeclaration(); 256 if (typeDeclarationSymbolReference.isSolved()) { 257 return SymbolReference.solved(annotationDeclaration); 258 } else { 259 return SymbolReference.unsolved(ResolvedAnnotationDeclaration.class); 260 } 261 } 262 263 public SymbolReference<ResolvedFieldDeclaration> solve(FieldAccessExpr fieldAccessExpr) { 264 return ((FieldAccessContext) JavaParserFactory.getContext(fieldAccessExpr, typeSolver)).solveField(fieldAccessExpr.getName().getId(), typeSolver); 265 } 266 267 public ResolvedType getType(Node node) { 268 return getType(node, true); 269 } 270 271 public ResolvedType getType(Node node, boolean solveLambdas) { 272 if (solveLambdas) { 273 if (!cacheWithLambdasSolved.containsKey(node)) { 274 ResolvedType res = getTypeConcrete(node, solveLambdas); 275 276 cacheWithLambdasSolved.put(node, res); 277 278 boolean secondPassNecessary = false; 279 if (node instanceof MethodCallExpr) { 280 MethodCallExpr methodCallExpr = (MethodCallExpr) node; 281 for (Node arg : methodCallExpr.getArguments()) { 282 if (!cacheWithLambdasSolved.containsKey(arg)) { 283 getType(arg, true); 284 secondPassNecessary = true; 285 } 286 } 287 } 288 if (secondPassNecessary) { 289 cacheWithLambdasSolved.remove(node); 290 cacheWithLambdasSolved.put(node, getType(node, true)); 291 } 292 logger.finer("getType on " + node + " -> " + res); 293 } 294 return cacheWithLambdasSolved.get(node); 295 } else { 296 Optional<ResolvedType> res = find(cacheWithLambdasSolved, node); 297 if (res.isPresent()) { 298 return res.get(); 299 } 300 res = find(cacheWithoutLambdasSolved, node); 301 if (!res.isPresent()) { 302 ResolvedType resType = getTypeConcrete(node, solveLambdas); 303 cacheWithoutLambdasSolved.put(node, resType); 304 logger.finer("getType on " + node + " (no solveLambdas) -> " + res); 305 return resType; 306 } 307 return res.get(); 308 } 309 } 310 311 private Optional<ResolvedType> find(Map<Node, ResolvedType> map, Node node) { 312 if (map.containsKey(node)) { 313 return Optional.of(map.get(node)); 314 } 315 if (node instanceof LambdaExpr) { 316 return find(map, (LambdaExpr) node); 317 } else { 318 return Optional.empty(); 319 } 320 } 321 322 /** 323 * For some reasons LambdaExprs are duplicate and the equals method is not implemented correctly. 324 */ 325 private Optional<ResolvedType> find(Map<Node, ResolvedType> map, LambdaExpr lambdaExpr) { 326 for (Node key : map.keySet()) { 327 if (key instanceof LambdaExpr) { 328 LambdaExpr keyLambdaExpr = (LambdaExpr) key; 329 if (keyLambdaExpr.toString().equals(lambdaExpr.toString()) && requireParentNode(keyLambdaExpr) == requireParentNode(lambdaExpr)) { 330 return Optional.of(map.get(keyLambdaExpr)); 331 } 332 } 333 } 334 return Optional.empty(); 335 } 336 337 protected MethodUsage toMethodUsage(MethodReferenceExpr methodReferenceExpr) { 338 if (!(methodReferenceExpr.getScope() instanceof TypeExpr)) { 339 throw new UnsupportedOperationException(); 340 } 341 TypeExpr typeExpr = (TypeExpr) methodReferenceExpr.getScope(); 342 if (!(typeExpr.getType() instanceof com.github.javaparser.ast.type.ClassOrInterfaceType)) { 343 throw new UnsupportedOperationException(typeExpr.getType().getClass().getCanonicalName()); 344 } 345 ClassOrInterfaceType classOrInterfaceType = (ClassOrInterfaceType) typeExpr.getType(); 346 SymbolReference<ResolvedTypeDeclaration> typeDeclarationSymbolReference = JavaParserFactory.getContext(classOrInterfaceType, typeSolver).solveType(classOrInterfaceType.getName().getId(), typeSolver); 347 if (!typeDeclarationSymbolReference.isSolved()) { 348 throw new UnsupportedOperationException(); 349 } 350 List<MethodUsage> methodUsages = ((ResolvedReferenceTypeDeclaration) typeDeclarationSymbolReference.getCorrespondingDeclaration()).getAllMethods().stream().filter(it -> it.getName().equals(methodReferenceExpr.getIdentifier())).collect(Collectors.toList()); 351 switch (methodUsages.size()) { 352 case 0: 353 throw new UnsupportedOperationException(); 354 case 1: 355 return methodUsages.get(0); 356 default: 357 throw new UnsupportedOperationException(); 358 } 359 } 360 361 protected ResolvedType getBinaryTypeConcrete(Node left, Node right, boolean solveLambdas) { 362 ResolvedType leftType = getTypeConcrete(left, solveLambdas); 363 ResolvedType rightType = getTypeConcrete(right, solveLambdas); 364 if (rightType.isAssignableBy(leftType)) { 365 return rightType; 366 } 367 return leftType; 368 } 369 370 371 /** 372 * Should return more like a TypeApplication: a TypeDeclaration and possible typeParametersValues or array 373 * modifiers. 374 */ 375 private ResolvedType getTypeConcrete(Node node, boolean solveLambdas) { 376 if (node == null) throw new IllegalArgumentException(); 377 return node.accept(typeExtractor, solveLambdas); 378 } 379 380 protected com.github.javaparser.ast.body.TypeDeclaration<?> findContainingTypeDecl(Node node) { 381 if (node instanceof ClassOrInterfaceDeclaration) { 382 return (ClassOrInterfaceDeclaration) node; 383 } 384 if (node instanceof EnumDeclaration) { 385 return (EnumDeclaration) node; 386 } 387 return findContainingTypeDecl(requireParentNode(node)); 388 389 } 390 391 protected Node findContainingTypeDeclOrObjectCreationExpr(Node node) { 392 if (node instanceof ClassOrInterfaceDeclaration) { 393 return node; 394 } 395 if (node instanceof EnumDeclaration) { 396 return node; 397 } 398 Node parent = requireParentNode(node); 399 if (parent instanceof ObjectCreationExpr && !((ObjectCreationExpr) parent).getArguments().contains(node)) { 400 return parent; 401 } 402 return findContainingTypeDeclOrObjectCreationExpr(parent); 403 } 404 405 public ResolvedType convertToUsageVariableType(VariableDeclarator var) { 406 return get(typeSolver).convertToUsage(var.getType(), var); 407 } 408 409 public ResolvedType convertToUsage(com.github.javaparser.ast.type.Type type, Node context) { 410 if (type.isUnknownType()) { 411 throw new IllegalArgumentException("Inferred lambda parameter type"); 412 } 413 return convertToUsage(type, JavaParserFactory.getContext(context, typeSolver)); 414 } 415 416 public ResolvedType convertToUsage(com.github.javaparser.ast.type.Type type) { 417 return convertToUsage(type, type); 418 } 419 420 // This is an hack around an issue in JavaParser 421 private String qName(ClassOrInterfaceType classOrInterfaceType) { 422 String name = classOrInterfaceType.getName().getId(); 423 if (classOrInterfaceType.getScope().isPresent()) { 424 return qName(classOrInterfaceType.getScope().get()) + "." + name; 425 } 426 return name; 427 } 428 429 protected ResolvedType convertToUsage(com.github.javaparser.ast.type.Type type, Context context) { 430 if (context == null) { 431 throw new NullPointerException("Context should not be null"); 432 } 433 if (type instanceof ClassOrInterfaceType) { 434 ClassOrInterfaceType classOrInterfaceType = (ClassOrInterfaceType) type; 435 String name = qName(classOrInterfaceType); 436 SymbolReference<ResolvedTypeDeclaration> ref = context.solveType(name, typeSolver); 437 if (!ref.isSolved()) { 438 throw new UnsolvedSymbolException(name); 439 } 440 ResolvedTypeDeclaration typeDeclaration = ref.getCorrespondingDeclaration(); 441 List<ResolvedType> typeParameters = Collections.emptyList(); 442 if (classOrInterfaceType.getTypeArguments().isPresent()) { 443 typeParameters = classOrInterfaceType.getTypeArguments().get().stream().map((pt) -> convertToUsage(pt, context)).collect(Collectors.toList()); 444 } 445 if (typeDeclaration.isTypeParameter()) { 446 if (typeDeclaration instanceof ResolvedTypeParameterDeclaration) { 447 return new ResolvedTypeVariable((ResolvedTypeParameterDeclaration) typeDeclaration); 448 } else { 449 JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) typeDeclaration; 450 return new ResolvedTypeVariable(javaParserTypeVariableDeclaration.asTypeParameter()); 451 } 452 } else { 453 return new ReferenceTypeImpl((ResolvedReferenceTypeDeclaration) typeDeclaration, typeParameters, typeSolver); 454 } 455 } else if (type instanceof com.github.javaparser.ast.type.PrimitiveType) { 456 return ResolvedPrimitiveType.byName(((com.github.javaparser.ast.type.PrimitiveType) type).getType().name()); 457 } else if (type instanceof WildcardType) { 458 WildcardType wildcardType = (WildcardType) type; 459 if (wildcardType.getExtendedType().isPresent() && !wildcardType.getSuperType().isPresent()) { 460 return ResolvedWildcard.extendsBound(convertToUsage(wildcardType.getExtendedType().get(), context)); // removed (ReferenceTypeImpl) 461 } else if (!wildcardType.getExtendedType().isPresent() && wildcardType.getSuperType().isPresent()) { 462 return ResolvedWildcard.superBound(convertToUsage(wildcardType.getSuperType().get(), context)); // removed (ReferenceTypeImpl) 463 } else if (!wildcardType.getExtendedType().isPresent() && !wildcardType.getSuperType().isPresent()) { 464 return ResolvedWildcard.UNBOUNDED; 465 } else { 466 throw new UnsupportedOperationException(wildcardType.toString()); 467 } 468 } else if (type instanceof com.github.javaparser.ast.type.VoidType) { 469 return ResolvedVoidType.INSTANCE; 470 } else if (type instanceof com.github.javaparser.ast.type.ArrayType) { 471 com.github.javaparser.ast.type.ArrayType jpArrayType = (com.github.javaparser.ast.type.ArrayType) type; 472 return new ResolvedArrayType(convertToUsage(jpArrayType.getComponentType(), context)); 473 } else if (type instanceof UnionType) { 474 UnionType unionType = (UnionType) type; 475 return new ResolvedUnionType(unionType.getElements().stream().map(el -> convertToUsage(el, context)).collect(Collectors.toList())); 476 } else if (type instanceof VarType) { 477 Node parent = type.getParentNode().get(); 478 if (!(parent instanceof VariableDeclarator)) { 479 throw new IllegalStateException("Trying to resolve a `var` which is not in a variable declaration."); 480 } 481 final VariableDeclarator variableDeclarator = (VariableDeclarator) parent; 482 return variableDeclarator.getInitializer() 483 .map(Expression::calculateResolvedType) 484 .orElseThrow(() -> new IllegalStateException("Cannot resolve `var` which has no initializer.")); 485 } else { 486 throw new UnsupportedOperationException(type.getClass().getCanonicalName()); 487 } 488 } 489 490 491 public ResolvedType convert(Type type, Node node) { 492 return convert(type, JavaParserFactory.getContext(node, typeSolver)); 493 } 494 495 public ResolvedType convert(com.github.javaparser.ast.type.Type type, Context context) { 496 return convertToUsage(type, context); 497 } 498 499 public MethodUsage solveMethodAsUsage(MethodCallExpr call) { 500 List<ResolvedType> params = new ArrayList<>(); 501 if (call.getArguments() != null) { 502 for (Expression param : call.getArguments()) { 503 //getTypeConcrete(Node node, boolean solveLambdas) 504 try { 505 params.add(getType(param, false)); 506 } catch (Exception e) { 507 throw new RuntimeException(String.format("Error calculating the type of parameter %s of method call %s", param, call), e); 508 } 509 //params.add(getTypeConcrete(param, false)); 510 } 511 } 512 Context context = JavaParserFactory.getContext(call, typeSolver); 513 Optional<MethodUsage> methodUsage = context.solveMethodAsUsage(call.getName().getId(), params, typeSolver); 514 if (!methodUsage.isPresent()) { 515 throw new RuntimeException("Method '" + call.getName() + "' cannot be resolved in context " 516 + call + " (line: " + call.getRange().map(r -> "" + r.begin.line).orElse("??") + ") " + context + ". Parameter types: " + params); 517 } 518 return methodUsage.get(); 519 } 520 521 public ResolvedReferenceTypeDeclaration getTypeDeclaration(Node node) { 522 if (node instanceof TypeDeclaration) { 523 return getTypeDeclaration((TypeDeclaration) node); 524 } else if (node instanceof ObjectCreationExpr) { 525 return new JavaParserAnonymousClassDeclaration((ObjectCreationExpr) node, typeSolver); 526 } else { 527 throw new IllegalArgumentException(); 528 } 529 } 530 531 public ResolvedReferenceTypeDeclaration getTypeDeclaration(ClassOrInterfaceDeclaration classOrInterfaceDeclaration) { 532 return JavaParserFactory.toTypeDeclaration(classOrInterfaceDeclaration, typeSolver); 533 } 534 535 /** 536 * "this" inserted in the given point, which type would have? 537 */ 538 public ResolvedType getTypeOfThisIn(Node node) { 539 // TODO consider static methods 540 if (node instanceof ClassOrInterfaceDeclaration) { 541 return new ReferenceTypeImpl(getTypeDeclaration((ClassOrInterfaceDeclaration) node), typeSolver); 542 } else if (node instanceof EnumDeclaration) { 543 JavaParserEnumDeclaration enumDeclaration = new JavaParserEnumDeclaration((EnumDeclaration) node, typeSolver); 544 return new ReferenceTypeImpl(enumDeclaration, typeSolver); 545 } else if (node instanceof ObjectCreationExpr && ((ObjectCreationExpr) node).getAnonymousClassBody().isPresent()) { 546 JavaParserAnonymousClassDeclaration anonymousDeclaration = new JavaParserAnonymousClassDeclaration((ObjectCreationExpr) node, typeSolver); 547 return new ReferenceTypeImpl(anonymousDeclaration, typeSolver); 548 } 549 return getTypeOfThisIn(requireParentNode(node)); 550 } 551 552 public ResolvedReferenceTypeDeclaration getTypeDeclaration(com.github.javaparser.ast.body.TypeDeclaration<?> typeDeclaration) { 553 return JavaParserFactory.toTypeDeclaration(typeDeclaration, typeSolver); 554 } 555 556 public ResolvedType classToResolvedType(Class<?> clazz) { 557 if (clazz.isPrimitive()) { 558 return ResolvedPrimitiveType.byName(clazz.getName()); 559 } 560 return new ReferenceTypeImpl(new ReflectionClassDeclaration(String.class, typeSolver), typeSolver); 561 } 562 } 563