aboutsummaryrefslogtreecommitdiffstats
path: root/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java
diff options
context:
space:
mode:
Diffstat (limited to 'javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java')
-rw-r--r--javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java562
1 files changed, 562 insertions, 0 deletions
diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java
new file mode 100644
index 000000000..f73dd986c
--- /dev/null
+++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2016 Federico Tomassetti
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.github.javaparser.symbolsolver.javaparsermodel;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.body.*;
+import com.github.javaparser.ast.body.EnumDeclaration;
+import com.github.javaparser.ast.expr.*;
+import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
+import com.github.javaparser.ast.type.*;
+import com.github.javaparser.resolution.MethodUsage;
+import com.github.javaparser.resolution.UnsolvedSymbolException;
+import com.github.javaparser.resolution.declarations.*;
+import com.github.javaparser.resolution.types.*;
+import com.github.javaparser.symbolsolver.core.resolution.Context;
+import com.github.javaparser.symbolsolver.javaparsermodel.contexts.FieldAccessContext;
+import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*;
+import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
+import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
+import com.github.javaparser.symbolsolver.model.typesystem.*;
+import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
+import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic;
+import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
+
+import java.util.*;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode;
+
+/**
+ * Class to be used by final users to solve symbols for JavaParser ASTs.
+ *
+ * @author Federico Tomassetti
+ */
+public class JavaParserFacade {
+
+ private static Logger logger = Logger.getLogger(JavaParserFacade.class.getCanonicalName());
+
+ static {
+ logger.setLevel(Level.INFO);
+ ConsoleHandler consoleHandler = new ConsoleHandler();
+ consoleHandler.setLevel(Level.INFO);
+ logger.addHandler(consoleHandler);
+ }
+
+ private static Map<TypeSolver, JavaParserFacade> instances = new WeakHashMap<>();
+ private TypeSolver typeSolver;
+ private SymbolSolver symbolSolver;
+ private Map<Node, ResolvedType> cacheWithLambdasSolved = new IdentityHashMap<>();
+ private Map<Node, ResolvedType> cacheWithoutLambdasSolved = new IdentityHashMap<>();
+ private TypeExtractor typeExtractor;
+
+ private JavaParserFacade(TypeSolver typeSolver) {
+ this.typeSolver = typeSolver.getRoot();
+ this.symbolSolver = new SymbolSolver(typeSolver);
+ this.typeExtractor = new TypeExtractor(typeSolver, this);
+ }
+
+ public TypeSolver getTypeSolver() {
+ return typeSolver;
+ }
+
+ public SymbolSolver getSymbolSolver() {
+ return symbolSolver;
+ }
+
+ public static JavaParserFacade get(TypeSolver typeSolver) {
+ return instances.computeIfAbsent(typeSolver, JavaParserFacade::new);
+ }
+
+ /**
+ * This method is used to clear internal caches for the sake of releasing memory.
+ */
+ public static void clearInstances() {
+ instances.clear();
+ }
+
+ protected static ResolvedType solveGenericTypes(ResolvedType type, Context context, TypeSolver typeSolver) {
+ if (type.isTypeVariable()) {
+ return context.solveGenericType(type.describe(), typeSolver).orElse(type);
+ }
+ if (type.isWildcard()) {
+ if (type.asWildcard().isExtends() || type.asWildcard().isSuper()) {
+ ResolvedWildcard wildcardUsage = type.asWildcard();
+ ResolvedType boundResolved = solveGenericTypes(wildcardUsage.getBoundedType(), context, typeSolver);
+ if (wildcardUsage.isExtends()) {
+ return ResolvedWildcard.extendsBound(boundResolved);
+ } else {
+ return ResolvedWildcard.superBound(boundResolved);
+ }
+ }
+ }
+ return type;
+ }
+
+ public SymbolReference<? extends ResolvedValueDeclaration> solve(NameExpr nameExpr) {
+ return symbolSolver.solveSymbol(nameExpr.getName().getId(), nameExpr);
+ }
+
+ public SymbolReference<? extends ResolvedValueDeclaration> solve(SimpleName nameExpr) {
+ return symbolSolver.solveSymbol(nameExpr.getId(), nameExpr);
+ }
+
+ public SymbolReference<? extends ResolvedValueDeclaration> solve(Expression expr) {
+ return expr.toNameExpr().map(this::solve).orElseThrow(() -> new IllegalArgumentException(expr.getClass().getCanonicalName()));
+ }
+
+ public SymbolReference<ResolvedMethodDeclaration> solve(MethodCallExpr methodCallExpr) {
+ return solve(methodCallExpr, true);
+ }
+
+ public SymbolReference<ResolvedConstructorDeclaration> solve(ObjectCreationExpr objectCreationExpr) {
+ return solve(objectCreationExpr, true);
+ }
+
+ public SymbolReference<ResolvedConstructorDeclaration> solve(ExplicitConstructorInvocationStmt explicitConstructorInvocationStmt) {
+ return solve(explicitConstructorInvocationStmt, true);
+ }
+
+ public SymbolReference<ResolvedConstructorDeclaration> solve(ExplicitConstructorInvocationStmt explicitConstructorInvocationStmt, boolean solveLambdas) {
+ List<ResolvedType> argumentTypes = new LinkedList<>();
+ List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>();
+
+ solveArguments(explicitConstructorInvocationStmt, explicitConstructorInvocationStmt.getArguments(), solveLambdas, argumentTypes, placeholders);
+
+ Optional<ClassOrInterfaceDeclaration> optAncestor = explicitConstructorInvocationStmt.getAncestorOfType(ClassOrInterfaceDeclaration.class);
+ if (!optAncestor.isPresent()) {
+ return SymbolReference.unsolved(ResolvedConstructorDeclaration.class);
+ }
+ ClassOrInterfaceDeclaration classNode = optAncestor.get();
+ ResolvedTypeDeclaration typeDecl = null;
+ if (!explicitConstructorInvocationStmt.isThis()) {
+ ResolvedType classDecl = JavaParserFacade.get(typeSolver).convert(classNode.getExtendedTypes(0), classNode);
+ if (classDecl.isReferenceType()) {
+ typeDecl = classDecl.asReferenceType().getTypeDeclaration();
+ }
+ } else {
+ SymbolReference<ResolvedTypeDeclaration> sr = JavaParserFactory.getContext(classNode, typeSolver).solveType(classNode.getNameAsString(), typeSolver);
+ if (sr.isSolved()) {
+ typeDecl = sr.getCorrespondingDeclaration();
+ }
+ }
+ if (typeDecl == null) {
+ return SymbolReference.unsolved(ResolvedConstructorDeclaration.class);
+ }
+ SymbolReference<ResolvedConstructorDeclaration> res = ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) typeDecl).getConstructors(), argumentTypes, typeSolver);
+ for (LambdaArgumentTypePlaceholder placeholder : placeholders) {
+ placeholder.setMethod(res);
+ }
+ return res;
+ }
+
+ public SymbolReference<ResolvedTypeDeclaration> solve(ThisExpr node) {
+ // If 'this' is prefixed by a class eg. MyClass.this
+ if (node.getClassExpr().isPresent()) {
+ // Get the class name
+ String className = node.getClassExpr().get().toString();
+ // Attempt to resolve using a typeSolver
+ SymbolReference<ResolvedReferenceTypeDeclaration> clazz = typeSolver.tryToSolveType(className);
+ if (clazz.isSolved()) {
+ return SymbolReference.solved(clazz.getCorrespondingDeclaration());
+ }
+ // Attempt to resolve locally in Compilation unit
+ Optional<CompilationUnit> cu = node.getAncestorOfType(CompilationUnit.class);
+ if (cu.isPresent()) {
+ Optional<ClassOrInterfaceDeclaration> classByName = cu.get().getClassByName(className);
+ if (classByName.isPresent()) {
+ return SymbolReference.solved(getTypeDeclaration(classByName.get()));
+ }
+ }
+ }
+ return SymbolReference.solved(getTypeDeclaration(findContainingTypeDeclOrObjectCreationExpr(node)));
+ }
+
+ /**
+ * Given a constructor call find out to which constructor declaration it corresponds.
+ */
+ public SymbolReference<ResolvedConstructorDeclaration> solve(ObjectCreationExpr objectCreationExpr, boolean solveLambdas) {
+ List<ResolvedType> argumentTypes = new LinkedList<>();
+ List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>();
+
+ solveArguments(objectCreationExpr, objectCreationExpr.getArguments(), solveLambdas, argumentTypes, placeholders);
+
+ ResolvedType classDecl = JavaParserFacade.get(typeSolver).convert(objectCreationExpr.getType(), objectCreationExpr);
+ if (!classDecl.isReferenceType()) {
+ return SymbolReference.unsolved(ResolvedConstructorDeclaration.class);
+ }
+ SymbolReference<ResolvedConstructorDeclaration> res = ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) classDecl.asReferenceType().getTypeDeclaration()).getConstructors(), argumentTypes, typeSolver);
+ for (LambdaArgumentTypePlaceholder placeholder : placeholders) {
+ placeholder.setMethod(res);
+ }
+ return res;
+ }
+
+ private void solveArguments(Node node, NodeList<Expression> args, boolean solveLambdas, List<ResolvedType> argumentTypes,
+ List<LambdaArgumentTypePlaceholder> placeholders) {
+ int i = 0;
+ for (Expression parameterValue : args) {
+ if (parameterValue instanceof LambdaExpr || parameterValue instanceof MethodReferenceExpr) {
+ LambdaArgumentTypePlaceholder placeholder = new LambdaArgumentTypePlaceholder(i);
+ argumentTypes.add(placeholder);
+ placeholders.add(placeholder);
+ } else {
+ try {
+ argumentTypes.add(JavaParserFacade.get(typeSolver).getType(parameterValue, solveLambdas));
+ } catch (com.github.javaparser.resolution.UnsolvedSymbolException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(String.format("Unable to calculate the type of a parameter of a method call. Method call: %s, Parameter: %s",
+ node, parameterValue), e);
+ }
+ }
+ i++;
+ }
+ }
+
+ /**
+ * Given a method call find out to which method declaration it corresponds.
+ */
+ public SymbolReference<ResolvedMethodDeclaration> solve(MethodCallExpr methodCallExpr, boolean solveLambdas) {
+ List<ResolvedType> argumentTypes = new LinkedList<>();
+ List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>();
+
+ solveArguments(methodCallExpr, methodCallExpr.getArguments(), solveLambdas, argumentTypes, placeholders);
+
+ SymbolReference<ResolvedMethodDeclaration> res = JavaParserFactory.getContext(methodCallExpr, typeSolver).solveMethod(methodCallExpr.getName().getId(), argumentTypes, false, typeSolver);
+ for (LambdaArgumentTypePlaceholder placeholder : placeholders) {
+ placeholder.setMethod(res);
+ }
+ return res;
+ }
+
+ public SymbolReference<ResolvedAnnotationDeclaration> solve(AnnotationExpr annotationExpr) {
+ Context context = JavaParserFactory.getContext(annotationExpr, typeSolver);
+ SymbolReference<ResolvedTypeDeclaration> typeDeclarationSymbolReference = context.solveType(annotationExpr.getNameAsString(), typeSolver);
+ ResolvedAnnotationDeclaration annotationDeclaration = (ResolvedAnnotationDeclaration) typeDeclarationSymbolReference.getCorrespondingDeclaration();
+ if (typeDeclarationSymbolReference.isSolved()) {
+ return SymbolReference.solved(annotationDeclaration);
+ } else {
+ return SymbolReference.unsolved(ResolvedAnnotationDeclaration.class);
+ }
+ }
+
+ public SymbolReference<ResolvedFieldDeclaration> solve(FieldAccessExpr fieldAccessExpr) {
+ return ((FieldAccessContext) JavaParserFactory.getContext(fieldAccessExpr, typeSolver)).solveField(fieldAccessExpr.getName().getId(), typeSolver);
+ }
+
+ public ResolvedType getType(Node node) {
+ return getType(node, true);
+ }
+
+ public ResolvedType getType(Node node, boolean solveLambdas) {
+ if (solveLambdas) {
+ if (!cacheWithLambdasSolved.containsKey(node)) {
+ ResolvedType res = getTypeConcrete(node, solveLambdas);
+
+ cacheWithLambdasSolved.put(node, res);
+
+ boolean secondPassNecessary = false;
+ if (node instanceof MethodCallExpr) {
+ MethodCallExpr methodCallExpr = (MethodCallExpr) node;
+ for (Node arg : methodCallExpr.getArguments()) {
+ if (!cacheWithLambdasSolved.containsKey(arg)) {
+ getType(arg, true);
+ secondPassNecessary = true;
+ }
+ }
+ }
+ if (secondPassNecessary) {
+ cacheWithLambdasSolved.remove(node);
+ cacheWithLambdasSolved.put(node, getType(node, true));
+ }
+ logger.finer("getType on " + node + " -> " + res);
+ }
+ return cacheWithLambdasSolved.get(node);
+ } else {
+ Optional<ResolvedType> res = find(cacheWithLambdasSolved, node);
+ if (res.isPresent()) {
+ return res.get();
+ }
+ res = find(cacheWithoutLambdasSolved, node);
+ if (!res.isPresent()) {
+ ResolvedType resType = getTypeConcrete(node, solveLambdas);
+ cacheWithoutLambdasSolved.put(node, resType);
+ logger.finer("getType on " + node + " (no solveLambdas) -> " + res);
+ return resType;
+ }
+ return res.get();
+ }
+ }
+
+ private Optional<ResolvedType> find(Map<Node, ResolvedType> map, Node node) {
+ if (map.containsKey(node)) {
+ return Optional.of(map.get(node));
+ }
+ if (node instanceof LambdaExpr) {
+ return find(map, (LambdaExpr) node);
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ /**
+ * For some reasons LambdaExprs are duplicate and the equals method is not implemented correctly.
+ */
+ private Optional<ResolvedType> find(Map<Node, ResolvedType> map, LambdaExpr lambdaExpr) {
+ for (Node key : map.keySet()) {
+ if (key instanceof LambdaExpr) {
+ LambdaExpr keyLambdaExpr = (LambdaExpr) key;
+ if (keyLambdaExpr.toString().equals(lambdaExpr.toString()) && requireParentNode(keyLambdaExpr) == requireParentNode(lambdaExpr)) {
+ return Optional.of(map.get(keyLambdaExpr));
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ protected MethodUsage toMethodUsage(MethodReferenceExpr methodReferenceExpr) {
+ if (!(methodReferenceExpr.getScope() instanceof TypeExpr)) {
+ throw new UnsupportedOperationException();
+ }
+ TypeExpr typeExpr = (TypeExpr) methodReferenceExpr.getScope();
+ if (!(typeExpr.getType() instanceof com.github.javaparser.ast.type.ClassOrInterfaceType)) {
+ throw new UnsupportedOperationException(typeExpr.getType().getClass().getCanonicalName());
+ }
+ ClassOrInterfaceType classOrInterfaceType = (ClassOrInterfaceType) typeExpr.getType();
+ SymbolReference<ResolvedTypeDeclaration> typeDeclarationSymbolReference = JavaParserFactory.getContext(classOrInterfaceType, typeSolver).solveType(classOrInterfaceType.getName().getId(), typeSolver);
+ if (!typeDeclarationSymbolReference.isSolved()) {
+ throw new UnsupportedOperationException();
+ }
+ List<MethodUsage> methodUsages = ((ResolvedReferenceTypeDeclaration) typeDeclarationSymbolReference.getCorrespondingDeclaration()).getAllMethods().stream().filter(it -> it.getName().equals(methodReferenceExpr.getIdentifier())).collect(Collectors.toList());
+ switch (methodUsages.size()) {
+ case 0:
+ throw new UnsupportedOperationException();
+ case 1:
+ return methodUsages.get(0);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ protected ResolvedType getBinaryTypeConcrete(Node left, Node right, boolean solveLambdas) {
+ ResolvedType leftType = getTypeConcrete(left, solveLambdas);
+ ResolvedType rightType = getTypeConcrete(right, solveLambdas);
+ if (rightType.isAssignableBy(leftType)) {
+ return rightType;
+ }
+ return leftType;
+ }
+
+
+ /**
+ * Should return more like a TypeApplication: a TypeDeclaration and possible typeParametersValues or array
+ * modifiers.
+ */
+ private ResolvedType getTypeConcrete(Node node, boolean solveLambdas) {
+ if (node == null) throw new IllegalArgumentException();
+ return node.accept(typeExtractor, solveLambdas);
+ }
+
+ protected com.github.javaparser.ast.body.TypeDeclaration<?> findContainingTypeDecl(Node node) {
+ if (node instanceof ClassOrInterfaceDeclaration) {
+ return (ClassOrInterfaceDeclaration) node;
+ }
+ if (node instanceof EnumDeclaration) {
+ return (EnumDeclaration) node;
+ }
+ return findContainingTypeDecl(requireParentNode(node));
+
+ }
+
+ protected Node findContainingTypeDeclOrObjectCreationExpr(Node node) {
+ if (node instanceof ClassOrInterfaceDeclaration) {
+ return node;
+ }
+ if (node instanceof EnumDeclaration) {
+ return node;
+ }
+ Node parent = requireParentNode(node);
+ if (parent instanceof ObjectCreationExpr && !((ObjectCreationExpr) parent).getArguments().contains(node)) {
+ return parent;
+ }
+ return findContainingTypeDeclOrObjectCreationExpr(parent);
+ }
+
+ public ResolvedType convertToUsageVariableType(VariableDeclarator var) {
+ return get(typeSolver).convertToUsage(var.getType(), var);
+ }
+
+ public ResolvedType convertToUsage(com.github.javaparser.ast.type.Type type, Node context) {
+ if (type.isUnknownType()) {
+ throw new IllegalArgumentException("Inferred lambda parameter type");
+ }
+ return convertToUsage(type, JavaParserFactory.getContext(context, typeSolver));
+ }
+
+ public ResolvedType convertToUsage(com.github.javaparser.ast.type.Type type) {
+ return convertToUsage(type, type);
+ }
+
+ // This is an hack around an issue in JavaParser
+ private String qName(ClassOrInterfaceType classOrInterfaceType) {
+ String name = classOrInterfaceType.getName().getId();
+ if (classOrInterfaceType.getScope().isPresent()) {
+ return qName(classOrInterfaceType.getScope().get()) + "." + name;
+ }
+ return name;
+ }
+
+ protected ResolvedType convertToUsage(com.github.javaparser.ast.type.Type type, Context context) {
+ if (context == null) {
+ throw new NullPointerException("Context should not be null");
+ }
+ if (type instanceof ClassOrInterfaceType) {
+ ClassOrInterfaceType classOrInterfaceType = (ClassOrInterfaceType) type;
+ String name = qName(classOrInterfaceType);
+ SymbolReference<ResolvedTypeDeclaration> ref = context.solveType(name, typeSolver);
+ if (!ref.isSolved()) {
+ throw new UnsolvedSymbolException(name);
+ }
+ ResolvedTypeDeclaration typeDeclaration = ref.getCorrespondingDeclaration();
+ List<ResolvedType> typeParameters = Collections.emptyList();
+ if (classOrInterfaceType.getTypeArguments().isPresent()) {
+ typeParameters = classOrInterfaceType.getTypeArguments().get().stream().map((pt) -> convertToUsage(pt, context)).collect(Collectors.toList());
+ }
+ if (typeDeclaration.isTypeParameter()) {
+ if (typeDeclaration instanceof ResolvedTypeParameterDeclaration) {
+ return new ResolvedTypeVariable((ResolvedTypeParameterDeclaration) typeDeclaration);
+ } else {
+ JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) typeDeclaration;
+ return new ResolvedTypeVariable(javaParserTypeVariableDeclaration.asTypeParameter());
+ }
+ } else {
+ return new ReferenceTypeImpl((ResolvedReferenceTypeDeclaration) typeDeclaration, typeParameters, typeSolver);
+ }
+ } else if (type instanceof com.github.javaparser.ast.type.PrimitiveType) {
+ return ResolvedPrimitiveType.byName(((com.github.javaparser.ast.type.PrimitiveType) type).getType().name());
+ } else if (type instanceof WildcardType) {
+ WildcardType wildcardType = (WildcardType) type;
+ if (wildcardType.getExtendedType().isPresent() && !wildcardType.getSuperType().isPresent()) {
+ return ResolvedWildcard.extendsBound(convertToUsage(wildcardType.getExtendedType().get(), context)); // removed (ReferenceTypeImpl)
+ } else if (!wildcardType.getExtendedType().isPresent() && wildcardType.getSuperType().isPresent()) {
+ return ResolvedWildcard.superBound(convertToUsage(wildcardType.getSuperType().get(), context)); // removed (ReferenceTypeImpl)
+ } else if (!wildcardType.getExtendedType().isPresent() && !wildcardType.getSuperType().isPresent()) {
+ return ResolvedWildcard.UNBOUNDED;
+ } else {
+ throw new UnsupportedOperationException(wildcardType.toString());
+ }
+ } else if (type instanceof com.github.javaparser.ast.type.VoidType) {
+ return ResolvedVoidType.INSTANCE;
+ } else if (type instanceof com.github.javaparser.ast.type.ArrayType) {
+ com.github.javaparser.ast.type.ArrayType jpArrayType = (com.github.javaparser.ast.type.ArrayType) type;
+ return new ResolvedArrayType(convertToUsage(jpArrayType.getComponentType(), context));
+ } else if (type instanceof UnionType) {
+ UnionType unionType = (UnionType) type;
+ return new ResolvedUnionType(unionType.getElements().stream().map(el -> convertToUsage(el, context)).collect(Collectors.toList()));
+ } else if (type instanceof VarType) {
+ Node parent = type.getParentNode().get();
+ if (!(parent instanceof VariableDeclarator)) {
+ throw new IllegalStateException("Trying to resolve a `var` which is not in a variable declaration.");
+ }
+ final VariableDeclarator variableDeclarator = (VariableDeclarator) parent;
+ return variableDeclarator.getInitializer()
+ .map(Expression::calculateResolvedType)
+ .orElseThrow(() -> new IllegalStateException("Cannot resolve `var` which has no initializer."));
+ } else {
+ throw new UnsupportedOperationException(type.getClass().getCanonicalName());
+ }
+ }
+
+
+ public ResolvedType convert(Type type, Node node) {
+ return convert(type, JavaParserFactory.getContext(node, typeSolver));
+ }
+
+ public ResolvedType convert(com.github.javaparser.ast.type.Type type, Context context) {
+ return convertToUsage(type, context);
+ }
+
+ public MethodUsage solveMethodAsUsage(MethodCallExpr call) {
+ List<ResolvedType> params = new ArrayList<>();
+ if (call.getArguments() != null) {
+ for (Expression param : call.getArguments()) {
+ //getTypeConcrete(Node node, boolean solveLambdas)
+ try {
+ params.add(getType(param, false));
+ } catch (Exception e) {
+ throw new RuntimeException(String.format("Error calculating the type of parameter %s of method call %s", param, call), e);
+ }
+ //params.add(getTypeConcrete(param, false));
+ }
+ }
+ Context context = JavaParserFactory.getContext(call, typeSolver);
+ Optional<MethodUsage> methodUsage = context.solveMethodAsUsage(call.getName().getId(), params, typeSolver);
+ if (!methodUsage.isPresent()) {
+ throw new RuntimeException("Method '" + call.getName() + "' cannot be resolved in context "
+ + call + " (line: " + call.getRange().map(r -> "" + r.begin.line).orElse("??") + ") " + context + ". Parameter types: " + params);
+ }
+ return methodUsage.get();
+ }
+
+ public ResolvedReferenceTypeDeclaration getTypeDeclaration(Node node) {
+ if (node instanceof TypeDeclaration) {
+ return getTypeDeclaration((TypeDeclaration) node);
+ } else if (node instanceof ObjectCreationExpr) {
+ return new JavaParserAnonymousClassDeclaration((ObjectCreationExpr) node, typeSolver);
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public ResolvedReferenceTypeDeclaration getTypeDeclaration(ClassOrInterfaceDeclaration classOrInterfaceDeclaration) {
+ return JavaParserFactory.toTypeDeclaration(classOrInterfaceDeclaration, typeSolver);
+ }
+
+ /**
+ * "this" inserted in the given point, which type would have?
+ */
+ public ResolvedType getTypeOfThisIn(Node node) {
+ // TODO consider static methods
+ if (node instanceof ClassOrInterfaceDeclaration) {
+ return new ReferenceTypeImpl(getTypeDeclaration((ClassOrInterfaceDeclaration) node), typeSolver);
+ } else if (node instanceof EnumDeclaration) {
+ JavaParserEnumDeclaration enumDeclaration = new JavaParserEnumDeclaration((EnumDeclaration) node, typeSolver);
+ return new ReferenceTypeImpl(enumDeclaration, typeSolver);
+ } else if (node instanceof ObjectCreationExpr && ((ObjectCreationExpr) node).getAnonymousClassBody().isPresent()) {
+ JavaParserAnonymousClassDeclaration anonymousDeclaration = new JavaParserAnonymousClassDeclaration((ObjectCreationExpr) node, typeSolver);
+ return new ReferenceTypeImpl(anonymousDeclaration, typeSolver);
+ }
+ return getTypeOfThisIn(requireParentNode(node));
+ }
+
+ public ResolvedReferenceTypeDeclaration getTypeDeclaration(com.github.javaparser.ast.body.TypeDeclaration<?> typeDeclaration) {
+ return JavaParserFactory.toTypeDeclaration(typeDeclaration, typeSolver);
+ }
+
+ public ResolvedType classToResolvedType(Class<?> clazz) {
+ if (clazz.isPrimitive()) {
+ return ResolvedPrimitiveType.byName(clazz.getName());
+ }
+ return new ReferenceTypeImpl(new ReflectionClassDeclaration(String.class, typeSolver), typeSolver);
+ }
+}