All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.tomassetti.symbolsolver.javaparsermodel.JavaParserFacade Maven / Gradle / Ivy

The newest version!
package me.tomassetti.symbolsolver.javaparsermodel;

import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.UnknownType;
import com.github.javaparser.ast.type.WildcardType;
import javaslang.Tuple2;
import me.tomassetti.symbolsolver.javaparsermodel.declarations.*;
import me.tomassetti.symbolsolver.logic.FunctionalInterfaceLogic;
import me.tomassetti.symbolsolver.logic.GenericTypeInferenceLogic;
import me.tomassetti.symbolsolver.model.declarations.*;
import me.tomassetti.symbolsolver.model.declarations.MethodDeclaration;
import me.tomassetti.symbolsolver.model.declarations.TypeDeclaration;
import me.tomassetti.symbolsolver.model.usages.MethodUsage;
import me.tomassetti.symbolsolver.core.resolution.Context;
import me.tomassetti.symbolsolver.model.resolution.SymbolReference;
import me.tomassetti.symbolsolver.model.resolution.TypeSolver;
import me.tomassetti.symbolsolver.model.usages.typesystem.*;
import me.tomassetti.symbolsolver.model.usages.typesystem.TypeVariable;
import me.tomassetti.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import me.tomassetti.symbolsolver.resolution.SymbolSolver;
import me.tomassetti.symbolsolver.resolution.typesolvers.JreTypeSolver;

import java.util.*;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * Class to be used by final users to solve symbols for JavaParser ASTs.
 */
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 instances = new HashMap<>();
    private TypeSolver typeSolver;
    private SymbolSolver symbolSolver;
    private Map cacheWithLambdasSolved = new IdentityHashMap<>();
    private Map cacheWithoutLambadsSolved = new IdentityHashMap<>();

    private JavaParserFacade(TypeSolver typeSolver) {
        this.typeSolver = typeSolver.getRoot();
        this.symbolSolver = new SymbolSolver(typeSolver);
    }

    public static JavaParserFacade get(TypeSolver typeSolver) {
        if (!instances.containsKey(typeSolver)) {
            instances.put(typeSolver, new JavaParserFacade(typeSolver));
        }
        return instances.get(typeSolver);
    }

    /**
     * This method is used to clear internal caches for the sake of releasing memory.
     */
    public static void clearInstances() {
	    instances.clear();
    }

    private static Type solveGenericTypes(Type type, Context context, TypeSolver typeSolver) {
        if (type.isTypeVariable()) {
            Optional solved = context.solveGenericType(type.describe(), typeSolver);
            if (solved.isPresent()) {
                return solved.get();
            } else {
                return type;
            }
        } else if (type.isWildcard()) {
            if (type.asWildcard().isExtends() || type.asWildcard().isSuper()) {
                Wildcard wildcardUsage = type.asWildcard();
                Type boundResolved = solveGenericTypes(wildcardUsage.getBoundedType(), context, typeSolver);
                if (wildcardUsage.isExtends()) {
                    return Wildcard.extendsBound(boundResolved);
                } else {
                    return Wildcard.superBound(boundResolved);
                }
            } else {
                return type;
            }
        } else {
            Type result = type;
            int i = 0;
            if (result.isReferenceType()) {
                for (Type tp : type.asReferenceType().typeParametersValues()) {
                    result = result.asReferenceType().replaceParam(i, solveGenericTypes(tp, context, typeSolver));
                    i++;
                }
            }
            return result;
        }
    }

    public SymbolReference solve(NameExpr nameExpr) {
        return symbolSolver.solveSymbol(nameExpr.getName(), nameExpr);
    }

    public SymbolReference solve(Expression expr) {
        if (expr instanceof NameExpr) {
            return solve((NameExpr) expr);
        } else {
            throw new IllegalArgumentException(expr.getClass().getCanonicalName());
        }
    }

    public SymbolReference solve(MethodCallExpr methodCallExpr) {
        return solve(methodCallExpr, true);
    }

    /**
     * Given a method call find out to which method declaration it corresponds.
     */
    public SymbolReference solve(MethodCallExpr methodCallExpr, boolean solveLambdas) {
        List argumentTypes = new LinkedList<>();
        List placeholders = new LinkedList<>();
        int i = 0;
        for (Expression parameterValue : methodCallExpr.getArgs()) {
            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 (Exception e){
                    throw new RuntimeException(String.format("Unable to calculate the type of a parameter of a method call. Method call: %s, Parameter: %s",
                            methodCallExpr, parameterValue), e);
                }
            }
            i++;
        }
        SymbolReference res = JavaParserFactory.getContext(methodCallExpr, typeSolver).solveMethod(methodCallExpr.getName(), argumentTypes, typeSolver);
        for (LambdaArgumentTypePlaceholder placeholder : placeholders) {
            placeholder.setMethod(res);
        }
        return res;
    }

    public Type getType(Node node) {
        return getType(node, true);
    }

    public Type getType(Node node, boolean solveLambdas) {
        if (solveLambdas) {
            if (!cacheWithLambdasSolved.containsKey(node)) {
                Type res = getTypeConcrete(node, solveLambdas);

                cacheWithLambdasSolved.put(node, res);

                boolean secondPassNecessary = false;
                if (node instanceof MethodCallExpr) {
                    MethodCallExpr methodCallExpr = (MethodCallExpr)node;
                    for (Node arg : methodCallExpr.getArgs()) {
                        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 res = find(cacheWithLambdasSolved, node);
            if (res.isPresent()) {
                return res.get();
            }
            res = find(cacheWithoutLambadsSolved, node);
            if (!res.isPresent()) {
                Type resType = getTypeConcrete(node, solveLambdas);
                cacheWithoutLambadsSolved.put(node, resType);
                logger.finer("getType on " + node + " (no solveLambdas) -> " + res);
                return resType;
            }
            return res.get();
        }
    }

    private Optional find(Map 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.
     * @param map
     * @return
     */
    private Optional find(Map map, LambdaExpr lambdaExpr) {
        for (Node key : map.keySet()) {
            if (key instanceof LambdaExpr) {
                LambdaExpr keyLambdaExpr = (LambdaExpr)key;
                if (keyLambdaExpr.toString().equals(lambdaExpr.toString()) && keyLambdaExpr.getParentNode() == lambdaExpr.getParentNode()) {
                    return Optional.of(map.get(keyLambdaExpr));
                }
            }
        }
        return Optional.empty();
    }

    private 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.ReferenceType)) {
            throw new UnsupportedOperationException(typeExpr.getType().getClass().getCanonicalName());
        }
        com.github.javaparser.ast.type.ReferenceType referenceType = (com.github.javaparser.ast.type.ReferenceType)typeExpr.getType();
        if (!(referenceType.getType() instanceof ClassOrInterfaceType)) {
            throw new UnsupportedOperationException(referenceType.getType().getClass().getCanonicalName());
        }
        ClassOrInterfaceType classOrInterfaceType = (ClassOrInterfaceType)referenceType.getType();
        SymbolReference typeDeclarationSymbolReference = JavaParserFactory.getContext(classOrInterfaceType, typeSolver).solveType(classOrInterfaceType.getName(), typeSolver);
        if (!typeDeclarationSymbolReference.isSolved()) {
            throw new UnsupportedOperationException();
        }
        List methodUsages = 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();
        }
    }

    /**
     * Should return more like a TypeApplication: a TypeDeclaration and possible typeParametersValues or array modifiers.
     *
     * @return
     */
    private Type getTypeConcrete(Node node, boolean solveLambdas) {
        if (node == null) throw new IllegalArgumentException();
        if (node instanceof NameExpr) {
            NameExpr nameExpr = (NameExpr) node;
            logger.finest("getType on name expr " + node);
            Optional value = new SymbolSolver(typeSolver).solveSymbolAsValue(nameExpr.getName(), nameExpr);
            if (!value.isPresent()) {
                throw new UnsolvedSymbolException("Solving " + node, nameExpr.getName());
            } else {
                return value.get().getUsage();
            }
        } else if (node instanceof MethodCallExpr) {
            logger.finest("getType on method call " + node);
            // first solve the method
            MethodUsage ref = solveMethodAsUsage((MethodCallExpr) node);
            logger.finest("getType on method call " + node + " resolved to " + ref);
            logger.finest("getType on method call " + node + " return type is " + ref.returnType());
            return ref.returnType();
            // the type is the return type of the method
        } else if (node instanceof LambdaExpr) {
            if (node.getParentNode() instanceof MethodCallExpr) {
                MethodCallExpr callExpr = (MethodCallExpr) node.getParentNode();
                int pos = JavaParserSymbolDeclaration.getParamPos(node);
                SymbolReference refMethod = JavaParserFacade.get(typeSolver).solve(callExpr);
                if (!refMethod.isSolved()) {
                    throw new UnsolvedSymbolException(node.getParentNode().toString(), callExpr.getName());
                }
                logger.finest("getType on lambda expr " + refMethod.getCorrespondingDeclaration().getName());
                //logger.finest("Method param " + refMethod.getCorrespondingDeclaration().getParam(pos));
                if (solveLambdas) {
                    Type result = refMethod.getCorrespondingDeclaration().getParam(pos).getType();
                    // We need to replace the type variables
                    Context ctx = JavaParserFactory.getContext(node, typeSolver);
                    result = solveGenericTypes(result, ctx, typeSolver);

                    //We should find out which is the functional method (e.g., apply) and replace the params of the
                    //solveLambdas with it, to derive so the values. We should also consider the value returned by the
                    //lambdas
                    Optional functionalMethod = FunctionalInterfaceLogic.getFunctionalMethod(result);
                    if (functionalMethod.isPresent()) {
                        LambdaExpr lambdaExpr = (LambdaExpr) node;

                        List> formalActualTypePairs = new ArrayList<>();
                        if (lambdaExpr.getBody() instanceof ExpressionStmt) {
                            ExpressionStmt expressionStmt = (ExpressionStmt) lambdaExpr.getBody();
                            Type actualType = getType(expressionStmt.getExpression());
                            Type formalType = functionalMethod.get().returnType();
                            formalActualTypePairs.add(new Tuple2<>(formalType, actualType));
                            Map inferredTypes = GenericTypeInferenceLogic.inferGenericTypes(formalActualTypePairs);
                            for (String typeName : inferredTypes.keySet()) {
                                result = result.replaceParam(typeName, inferredTypes.get(typeName));
                            }
                        } else {
                            throw new UnsupportedOperationException();
                        }
                    }

                    return result;
                } else {
                    return refMethod.getCorrespondingDeclaration().getParam(pos).getType();
                }
            } else {
                throw new UnsupportedOperationException("The type of a lambda expr depends on the position and its return value");
            }
        } else if (node instanceof MethodReferenceExpr) {
            if (node.getParentNode() instanceof MethodCallExpr) {
                MethodCallExpr callExpr = (MethodCallExpr) node.getParentNode();
                int pos = JavaParserSymbolDeclaration.getParamPos(node);
                SymbolReference refMethod = JavaParserFacade.get(typeSolver).solve(callExpr, false);
                if (!refMethod.isSolved()) {
                    throw new UnsolvedSymbolException(node.getParentNode().toString(), callExpr.getName());
                }
                logger.finest("getType on method reference expr " + refMethod.getCorrespondingDeclaration().getName());
                //logger.finest("Method param " + refMethod.getCorrespondingDeclaration().getParam(pos));
                if (solveLambdas) {
                    Type result = refMethod.getCorrespondingDeclaration().getParam(pos).getType();
                    // We need to replace the type variables
                    Context ctx = JavaParserFactory.getContext(node, typeSolver);
                    result = solveGenericTypes(result, ctx, typeSolver);

                    //We should find out which is the functional method (e.g., apply) and replace the params of the
                    //solveLambdas with it, to derive so the values. We should also consider the value returned by the
                    //lambdas
                    Optional functionalMethod = FunctionalInterfaceLogic.getFunctionalMethod(result);
                    if (functionalMethod.isPresent()) {
                        if (node instanceof MethodReferenceExpr) {
                            MethodReferenceExpr methodReferenceExpr = (MethodReferenceExpr) node;

                            List> formalActualTypePairs = new ArrayList<>();
                            Type actualType = toMethodUsage(methodReferenceExpr).returnType();
                            Type formalType = functionalMethod.get().returnType();
                            formalActualTypePairs.add(new Tuple2<>(formalType, actualType));
                            Map inferredTypes = GenericTypeInferenceLogic.inferGenericTypes(formalActualTypePairs);
                            for (String typeName : inferredTypes.keySet()) {
                                result = result.replaceParam(typeName, inferredTypes.get(typeName));
                            }

                        } else {
                            LambdaExpr lambdaExpr = (LambdaExpr) node;

                            List> formalActualTypePairs = new ArrayList<>();
                            if (lambdaExpr.getBody() instanceof ExpressionStmt) {
                                ExpressionStmt expressionStmt = (ExpressionStmt) lambdaExpr.getBody();
                                Type actualType = getType(expressionStmt.getExpression());
                                Type formalType = functionalMethod.get().returnType();
                                formalActualTypePairs.add(new Tuple2<>(formalType, actualType));
                                Map inferredTypes = GenericTypeInferenceLogic.inferGenericTypes(formalActualTypePairs);
                                for (String typeName : inferredTypes.keySet()) {
                                    result = result.replaceParam(typeName, inferredTypes.get(typeName));
                                }
                            } else {
                                throw new UnsupportedOperationException();
                            }
                        }
                    }

                    return result;
                } else {
                    return refMethod.getCorrespondingDeclaration().getParam(pos).getType();
                }
            } else {
                throw new UnsupportedOperationException("The type of a method reference expr depends on the position and its return value");
            }
        } else if (node instanceof VariableDeclarator) {
            if (node.getParentNode() instanceof FieldDeclaration) {
                FieldDeclaration parent = (FieldDeclaration) node.getParentNode();
                return JavaParserFacade.get(typeSolver).convertToUsage(parent.getType(), parent);
            } else if (node.getParentNode() instanceof VariableDeclarationExpr) {
                VariableDeclarationExpr parent = (VariableDeclarationExpr) node.getParentNode();
                return JavaParserFacade.get(typeSolver).convertToUsage(parent.getType(), parent);
            } else {
                throw new UnsupportedOperationException(node.getParentNode().getClass().getCanonicalName());
            }
        } else if (node instanceof Parameter) {
            Parameter parameter = (Parameter) node;
            if (parameter.getType() instanceof UnknownType) {
                throw new IllegalStateException("Parameter has unknown type: " + parameter);
            }
            return JavaParserFacade.get(typeSolver).convertToUsage(parameter.getType(), parameter);
        } else if (node instanceof FieldAccessExpr) {
            FieldAccessExpr fieldAccessExpr = (FieldAccessExpr) node;
            // We should understand if this is a static access
            try {
                Optional value = new SymbolSolver(typeSolver).solveSymbolAsValue(fieldAccessExpr.getField(), fieldAccessExpr);
                if (value.isPresent()) {
                    return value.get().getUsage();
                } else {
                    throw new UnsolvedSymbolException(fieldAccessExpr.getField());
                }
            } catch (UnsolvedSymbolException e) {
                // Sure, it was not found as value because maybe it is a type and this is a static access
                if (fieldAccessExpr.getScope() instanceof NameExpr) {
                    NameExpr staticValue = (NameExpr) fieldAccessExpr.getScope();
                    SymbolReference typeAccessedStatically = JavaParserFactory.getContext(fieldAccessExpr, typeSolver).solveType(staticValue.toString(), typeSolver);
                    if (!typeAccessedStatically.isSolved()) {
                        throw e;
                    } else {
                        // TODO here maybe we have to substitute type typeParametersValues
                        return typeAccessedStatically.getCorrespondingDeclaration().getField(fieldAccessExpr.getField()).getType();
                    }
                } else {
                    throw e;
                }
            }
        } else if (node instanceof ObjectCreationExpr) {
            ObjectCreationExpr objectCreationExpr = (ObjectCreationExpr) node;
            Type type = JavaParserFacade.get(typeSolver).convertToUsage(objectCreationExpr.getType(), node);
            return type;
        } else if (node instanceof NullLiteralExpr) {
            return NullType.INSTANCE;
        } else if (node instanceof BooleanLiteralExpr) {
            return PrimitiveType.BOOLEAN;
        } else if (node instanceof IntegerLiteralExpr) {
            return PrimitiveType.INT;
        } else if (node instanceof LongLiteralExpr) {
            return PrimitiveType.LONG;
        } else if (node instanceof CharLiteralExpr) {
            return PrimitiveType.CHAR;
		} else if (node instanceof DoubleLiteralExpr) {
			return PrimitiveType.DOUBLE;
		} else if (node instanceof StringLiteralExpr) {
            return new ReferenceTypeImpl(new JreTypeSolver().solveType("java.lang.String"), typeSolver);
        } else if (node instanceof UnaryExpr) {
            UnaryExpr unaryExpr = (UnaryExpr) node;
            switch (unaryExpr.getOperator()) {
                case negative:
                case positive:
                    return getTypeConcrete(unaryExpr.getExpr(), solveLambdas);
                case not:
                    return PrimitiveType.BOOLEAN;
                case posIncrement:
                case preIncrement:
                case preDecrement:
                case posDecrement:
                    return getTypeConcrete(unaryExpr.getExpr(), solveLambdas);
                default:
                    throw new UnsupportedOperationException(unaryExpr.getOperator().name());
            }
        } else if (node instanceof BinaryExpr) {
            BinaryExpr binaryExpr = (BinaryExpr) node;
            switch (binaryExpr.getOperator()) {
                case plus:
                case minus:
                    return getTypeConcrete(binaryExpr.getLeft(), solveLambdas);
                case lessEquals:
                case less:
                case greater:
                case greaterEquals:
                case equals:
                case notEquals:
                case or:
                case and:
                    return PrimitiveType.BOOLEAN;
                case binAnd:
                case binOr:
                    return getTypeConcrete(binaryExpr.getLeft(), solveLambdas);
                default:
                    throw new UnsupportedOperationException("FOO " + binaryExpr.getOperator().name());
            }
        } else if (node instanceof VariableDeclarationExpr) {
            VariableDeclarationExpr expr = (VariableDeclarationExpr) node;
            return convertToUsage(expr.getType(), JavaParserFactory.getContext(node, typeSolver));
        } else if (node instanceof InstanceOfExpr) {
            return PrimitiveType.BOOLEAN;
        } else if (node instanceof EnclosedExpr) {
            EnclosedExpr enclosedExpr = (EnclosedExpr) node;
            return getTypeConcrete(enclosedExpr.getInner(), solveLambdas);
        } else if (node instanceof CastExpr) {
            CastExpr enclosedExpr = (CastExpr) node;
            return convertToUsage(enclosedExpr.getType(), JavaParserFactory.getContext(node, typeSolver));
        } else if (node instanceof AssignExpr) {
            AssignExpr assignExpr = (AssignExpr) node;
            return getTypeConcrete(assignExpr.getTarget(), solveLambdas);
        } else if (node instanceof ThisExpr) {
            return new ReferenceTypeImpl(getTypeDeclaration(findContainingTypeDecl(node)), typeSolver);
        } else if (node instanceof ConditionalExpr) {
            ConditionalExpr conditionalExpr = (ConditionalExpr) node;
            return getTypeConcrete(conditionalExpr.getThenExpr(), solveLambdas);
        } else if (node instanceof ArrayCreationExpr) {
            ArrayCreationExpr arrayCreationExpr = (ArrayCreationExpr) node;
            Type res = convertToUsage(arrayCreationExpr.getType(), JavaParserFactory.getContext(node, typeSolver));
            for (int i=0; i ref = context.solveType(name, typeSolver);
            if (!ref.isSolved()) {
                throw new UnsolvedSymbolException(name);
            }
            TypeDeclaration typeDeclaration = ref.getCorrespondingDeclaration();
            List typeParameters = Collections.emptyList();
            if (classOrInterfaceType.getTypeArgs() != null) {
                typeParameters = classOrInterfaceType.getTypeArgs().stream().map((pt) -> convertToUsage(pt, context)).collect(Collectors.toList());
            }
            if (typeDeclaration.isTypeVariable()) {
                if (typeDeclaration instanceof TypeParameterDeclaration) {
                    return new TypeVariable((TypeParameterDeclaration) typeDeclaration);
                } else {
                    JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) typeDeclaration;
                    return new TypeVariable(javaParserTypeVariableDeclaration.asTypeParameter());
                }
            } else {
                return new ReferenceTypeImpl(typeDeclaration, typeParameters, typeSolver);
            }
        } else if (type instanceof com.github.javaparser.ast.type.PrimitiveType) {
            return PrimitiveType.byName(((com.github.javaparser.ast.type.PrimitiveType) type).getType().name());
        } else if (type instanceof WildcardType) {
            WildcardType wildcardType = (WildcardType) type;
            if (wildcardType.getExtends() != null && wildcardType.getSuper() == null) {
                return Wildcard.extendsBound((ReferenceTypeImpl) convertToUsage(wildcardType.getExtends(), context));
            } else if (wildcardType.getExtends() == null && wildcardType.getSuper() != null) {
                return Wildcard.extendsBound((ReferenceTypeImpl) convertToUsage(wildcardType.getSuper(), context));
            } else if (wildcardType.getExtends() == null && wildcardType.getSuper() == null) {
                return Wildcard.UNBOUNDED;
            } else {
                throw new UnsupportedOperationException();
            }
        } else if (type instanceof com.github.javaparser.ast.type.VoidType) {
            return VoidType.INSTANCE;
        } else {
            throw new UnsupportedOperationException(type.getClass().getCanonicalName());
        }
    }


    public Type convert(com.github.javaparser.ast.type.Type type, Node node) {
        return convert(type, JavaParserFactory.getContext(node, typeSolver));
    }

    public Type convert(com.github.javaparser.ast.type.Type type, Context context) {
        return convertToUsage(type, context);
    }

    public MethodUsage solveMethodAsUsage(MethodCallExpr call) {
        List params = new ArrayList<>();
        if (call.getArgs() != null) {
            for (Expression param : call.getArgs()) {
                //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 = context.solveMethodAsUsage(call.getName(), params, typeSolver);
        if (!methodUsage.isPresent()) {
            throw new RuntimeException("Method '" + call.getName() + "' cannot be resolved in context "
                    + call + " (line: " + call.getRange().begin.line + ") " + context+". Parameter types: "+ params);
        }
        return methodUsage.get();
    }

    public TypeDeclaration getTypeDeclaration(ClassOrInterfaceDeclaration classOrInterfaceDeclaration) {
        if (classOrInterfaceDeclaration.isInterface()) {
            return new JavaParserInterfaceDeclaration(classOrInterfaceDeclaration, typeSolver);
        } else {
            return new JavaParserClassDeclaration(classOrInterfaceDeclaration, typeSolver);
        }
    }

    /**
     * "this" inserted in the given point, which type would have?
     */
    public Type 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 {
            return getTypeOfThisIn(node.getParentNode());
        }
    }

    public TypeDeclaration getTypeDeclaration(com.github.javaparser.ast.body.TypeDeclaration typeDeclaration) {
        if (typeDeclaration instanceof ClassOrInterfaceDeclaration) {
            return getTypeDeclaration((ClassOrInterfaceDeclaration) typeDeclaration);
        } else if (typeDeclaration instanceof EnumDeclaration) {
            return new JavaParserEnumDeclaration((EnumDeclaration) typeDeclaration, typeSolver);
        } else {
            throw new UnsupportedOperationException(typeDeclaration.getClass().getCanonicalName());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy