diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-03-04 08:21:35 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-03-04 08:21:35 +0000 |
commit | b4c1397d5df9370f6358d4f8e9efd27e0f67dec1 (patch) | |
tree | 6789ec288d344cf5fd5d057bcf1efc9545b1af28 /javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel | |
parent | 92d661a1d239131fb5c1e019a8f2ac7584d2d3f6 (diff) | |
parent | 1afe9e0652b9b53edade5aa276162abe27b32a67 (diff) | |
download | platform_external_javaparser-android-9.0.0_r7.tar.gz platform_external_javaparser-android-9.0.0_r7.tar.bz2 platform_external_javaparser-android-9.0.0_r7.zip |
Snap for 4632767 from 1afe9e0652b9b53edade5aa276162abe27b32a67 to pi-releaseandroid-wear-9.0.0_r9android-wear-9.0.0_r8android-wear-9.0.0_r7android-wear-9.0.0_r6android-wear-9.0.0_r5android-wear-9.0.0_r4android-wear-9.0.0_r3android-wear-9.0.0_r23android-wear-9.0.0_r22android-wear-9.0.0_r21android-wear-9.0.0_r20android-wear-9.0.0_r2android-wear-9.0.0_r19android-wear-9.0.0_r18android-wear-9.0.0_r17android-wear-9.0.0_r16android-wear-9.0.0_r15android-wear-9.0.0_r14android-wear-9.0.0_r13android-wear-9.0.0_r12android-wear-9.0.0_r11android-wear-9.0.0_r10android-wear-9.0.0_r1android-vts-9.0_r9android-vts-9.0_r8android-vts-9.0_r7android-vts-9.0_r6android-vts-9.0_r5android-vts-9.0_r4android-vts-9.0_r14android-vts-9.0_r13android-vts-9.0_r12android-vts-9.0_r11android-vts-9.0_r10android-cts-9.0_r9android-cts-9.0_r8android-cts-9.0_r7android-cts-9.0_r6android-cts-9.0_r5android-cts-9.0_r4android-cts-9.0_r3android-cts-9.0_r2android-cts-9.0_r13android-cts-9.0_r12android-cts-9.0_r11android-cts-9.0_r10android-cts-9.0_r1android-9.0.0_r9android-9.0.0_r8android-9.0.0_r7android-9.0.0_r60android-9.0.0_r6android-9.0.0_r59android-9.0.0_r58android-9.0.0_r57android-9.0.0_r56android-9.0.0_r55android-9.0.0_r54android-9.0.0_r53android-9.0.0_r52android-9.0.0_r51android-9.0.0_r50android-9.0.0_r5android-9.0.0_r49android-9.0.0_r48android-9.0.0_r3android-9.0.0_r2android-9.0.0_r18android-9.0.0_r17android-9.0.0_r10android-9.0.0_r1security-pi-releasepie-vts-releasepie-security-releasepie-s2-releasepie-release-2pie-releasepie-r2-s2-releasepie-r2-s1-releasepie-r2-releasepie-platform-releasepie-gsipie-cuttlefish-testingpie-cts-release
Change-Id: Ibe65883e94ed5a7272dff3f100393987a1cf3da2
Diffstat (limited to 'javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel')
48 files changed, 7461 insertions, 0 deletions
diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/DefaultVisitorAdapter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/DefaultVisitorAdapter.java new file mode 100644 index 000000000..499ef3bd0 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/DefaultVisitorAdapter.java @@ -0,0 +1,475 @@ +package com.github.javaparser.symbolsolver.javaparsermodel; + +import com.github.javaparser.ast.*; +import com.github.javaparser.ast.body.*; +import com.github.javaparser.ast.comments.BlockComment; +import com.github.javaparser.ast.comments.JavadocComment; +import com.github.javaparser.ast.comments.LineComment; +import com.github.javaparser.ast.expr.*; +import com.github.javaparser.ast.modules.*; +import com.github.javaparser.ast.stmt.*; +import com.github.javaparser.ast.type.*; +import com.github.javaparser.ast.visitor.GenericVisitor; +import com.github.javaparser.resolution.types.ResolvedType; + +public class DefaultVisitorAdapter implements GenericVisitor<ResolvedType, Boolean> { + @Override + public ResolvedType visit(CompilationUnit node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(PackageDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(TypeParameter node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(LineComment node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(BlockComment node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ClassOrInterfaceDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(EnumDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(EnumConstantDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(AnnotationDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(AnnotationMemberDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(FieldDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(VariableDeclarator node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ConstructorDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(MethodDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(Parameter node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(InitializerDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(JavadocComment node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ClassOrInterfaceType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(PrimitiveType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ArrayType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ArrayCreationLevel node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(IntersectionType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(UnionType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(VoidType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(WildcardType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(UnknownType node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ArrayAccessExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ArrayCreationExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ArrayInitializerExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(AssignExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(BinaryExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(CastExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ClassExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ConditionalExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(EnclosedExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(FieldAccessExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(InstanceOfExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(StringLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(IntegerLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(LongLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(CharLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(DoubleLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(BooleanLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(NullLiteralExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(MethodCallExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(NameExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ObjectCreationExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ThisExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(SuperExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(UnaryExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(VariableDeclarationExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(MarkerAnnotationExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(SingleMemberAnnotationExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(NormalAnnotationExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(MemberValuePair node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ExplicitConstructorInvocationStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(LocalClassDeclarationStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(AssertStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(BlockStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(LabeledStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(EmptyStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ExpressionStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(SwitchStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(SwitchEntryStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(BreakStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ReturnStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(IfStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(WhileStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ContinueStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(DoStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ForeachStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ForStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ThrowStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(SynchronizedStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(TryStmt node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(CatchClause node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(LambdaExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(MethodReferenceExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(TypeExpr node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(NodeList node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(Name node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(SimpleName node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ImportDeclaration node, Boolean aBoolean) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ModuleDeclaration node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ModuleRequiresStmt node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ModuleExportsStmt node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ModuleProvidesStmt node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ModuleUsesStmt node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ModuleOpensStmt node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(UnparsableStmt node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(ReceiverParameter node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(VarType node, Boolean arg) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } +} 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); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFactory.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFactory.java new file mode 100644 index 000000000..8bd3496fd --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFactory.java @@ -0,0 +1,139 @@ +/* + * 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.body.*; +import com.github.javaparser.ast.expr.*; +import com.github.javaparser.ast.stmt.*; +import com.github.javaparser.ast.type.TypeParameter; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.contexts.*; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnnotationDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserInterfaceDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; +import com.github.javaparser.symbolsolver.javaparsermodel.declarators.FieldSymbolDeclarator; +import com.github.javaparser.symbolsolver.javaparsermodel.declarators.NoSymbolDeclarator; +import com.github.javaparser.symbolsolver.javaparsermodel.declarators.ParameterSymbolDeclarator; +import com.github.javaparser.symbolsolver.javaparsermodel.declarators.VariableSymbolDeclarator; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserFactory { + + public static Context getContext(Node node, TypeSolver typeSolver) { + if (node == null) { + throw new NullPointerException("Node should not be null"); + } else if (node instanceof CompilationUnit) { + return new CompilationUnitContext((CompilationUnit) node, typeSolver); + } else if (node instanceof ForeachStmt) { + return new ForechStatementContext((ForeachStmt) node, typeSolver); + } else if (node instanceof ForStmt) { + return new ForStatementContext((ForStmt) node, typeSolver); + } else if (node instanceof LambdaExpr) { + return new LambdaExprContext((LambdaExpr) node, typeSolver); + } else if (node instanceof MethodDeclaration) { + return new MethodContext((MethodDeclaration) node, typeSolver); + } else if (node instanceof ConstructorDeclaration) { + return new ConstructorContext((ConstructorDeclaration) node, typeSolver); + } else if (node instanceof ClassOrInterfaceDeclaration) { + return new ClassOrInterfaceDeclarationContext((ClassOrInterfaceDeclaration) node, typeSolver); + } else if (node instanceof MethodCallExpr) { + return new MethodCallExprContext((MethodCallExpr) node, typeSolver); + } else if (node instanceof EnumDeclaration) { + return new EnumDeclarationContext((EnumDeclaration) node, typeSolver); + } else if (node instanceof FieldAccessExpr) { + return new FieldAccessContext((FieldAccessExpr) node, typeSolver); + } else if (node instanceof SwitchEntryStmt) { + return new SwitchEntryContext((SwitchEntryStmt) node, typeSolver); + } else if (node instanceof TryStmt) { + return new TryWithResourceContext((TryStmt) node, typeSolver); + } else if (node instanceof Statement) { + return new StatementContext<>((Statement) node, typeSolver); + } else if (node instanceof CatchClause) { + return new CatchClauseContext((CatchClause) node, typeSolver); + } else if (node instanceof ObjectCreationExpr && + ((ObjectCreationExpr) node).getAnonymousClassBody().isPresent()) { + return new AnonymousClassDeclarationContext((ObjectCreationExpr) node, typeSolver); + } else { + if (node instanceof NameExpr) { + // to resolve a name when in a fieldAccess context, we can get to the grand parent to prevent a infinite loop if the name is the same as the field (ie x.x) + if (node.getParentNode().isPresent() && node.getParentNode().get() instanceof FieldAccessExpr && node.getParentNode().get().getParentNode().isPresent()) { + return getContext(node.getParentNode().get().getParentNode().get(), typeSolver); + } + } + final Node parentNode = requireParentNode(node); + if (parentNode instanceof ObjectCreationExpr && node == ((ObjectCreationExpr) parentNode).getType()) { + return getContext(requireParentNode(parentNode), typeSolver); + } + if (parentNode == null) { + throw new IllegalStateException("The AST node does not appear to be inserted in a propert AST, therefore we cannot resolve symbols correctly"); + } + return getContext(parentNode, typeSolver); + } + } + + public static SymbolDeclarator getSymbolDeclarator(Node node, TypeSolver typeSolver) { + if (node instanceof FieldDeclaration) { + return new FieldSymbolDeclarator((FieldDeclaration) node, typeSolver); + } else if (node instanceof Parameter) { + return new ParameterSymbolDeclarator((Parameter) node, typeSolver); + } else if (node instanceof ExpressionStmt) { + ExpressionStmt expressionStmt = (ExpressionStmt) node; + if (expressionStmt.getExpression() instanceof VariableDeclarationExpr) { + return new VariableSymbolDeclarator((VariableDeclarationExpr) (expressionStmt.getExpression()), typeSolver); + } else { + return new NoSymbolDeclarator<>(expressionStmt, typeSolver); + } + } else if (node instanceof IfStmt) { + return new NoSymbolDeclarator<>((IfStmt) node, typeSolver); + } else if (node instanceof ForeachStmt) { + ForeachStmt foreachStmt = (ForeachStmt) node; + return new VariableSymbolDeclarator(foreachStmt.getVariable(), typeSolver); + } else { + return new NoSymbolDeclarator<>(node, typeSolver); + } + } + + public static ResolvedReferenceTypeDeclaration toTypeDeclaration(Node node, TypeSolver typeSolver) { + if (node instanceof ClassOrInterfaceDeclaration) { + if (((ClassOrInterfaceDeclaration) node).isInterface()) { + return new JavaParserInterfaceDeclaration((ClassOrInterfaceDeclaration) node, typeSolver); + } else { + return new JavaParserClassDeclaration((ClassOrInterfaceDeclaration) node, typeSolver); + } + } else if (node instanceof TypeParameter) { + return new JavaParserTypeParameter((TypeParameter) node, typeSolver); + } else if (node instanceof EnumDeclaration) { + return new JavaParserEnumDeclaration((EnumDeclaration) node, typeSolver); + } else if (node instanceof AnnotationDeclaration) { + return new JavaParserAnnotationDeclaration((AnnotationDeclaration) node, typeSolver); + } else { + throw new IllegalArgumentException(node.getClass().getCanonicalName()); + } + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/LambdaArgumentTypePlaceholder.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/LambdaArgumentTypePlaceholder.java new file mode 100644 index 000000000..c0e35bf43 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/LambdaArgumentTypePlaceholder.java @@ -0,0 +1,72 @@ +/* + * 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.resolution.declarations.ResolvedMethodLikeDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; + +/** + * Placeholder used to represent a lambda argument type while it is being + * calculated. + * + * @author Federico Tomassetti + */ +public class LambdaArgumentTypePlaceholder implements ResolvedType { + + private int pos; + private SymbolReference<? extends ResolvedMethodLikeDeclaration> method; + + public LambdaArgumentTypePlaceholder(int pos) { + this.pos = pos; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isPrimitive() { + return false; + } + + @Override + public boolean isReferenceType() { + return false; + } + + @Override + public String describe() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isTypeVariable() { + return false; + } + + public void setMethod(SymbolReference<? extends ResolvedMethodLikeDeclaration> method) { + this.method = method; + } + + @Override + public boolean isAssignableBy(ResolvedType other) { + throw new UnsupportedOperationException(); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/TypeExtractor.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/TypeExtractor.java new file mode 100644 index 000000000..44c8d2715 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/TypeExtractor.java @@ -0,0 +1,517 @@ +package com.github.javaparser.symbolsolver.javaparsermodel; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.*; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.UnknownType; +import com.github.javaparser.resolution.MethodUsage; +import com.github.javaparser.resolution.UnsolvedSymbolException; +import com.github.javaparser.resolution.declarations.ResolvedClassDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.types.ResolvedArrayType; +import com.github.javaparser.resolution.types.ResolvedPrimitiveType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.resolution.types.ResolvedVoidType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.logic.FunctionalInterfaceLogic; +import com.github.javaparser.symbolsolver.logic.InferenceContext; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.model.typesystem.*; +import com.github.javaparser.symbolsolver.reflectionmodel.MyObjectProvider; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Optional; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; +import static com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solveGenericTypes; + +public class TypeExtractor extends DefaultVisitorAdapter { + + private static Logger logger = Logger.getLogger(TypeExtractor.class.getCanonicalName()); + + static { + logger.setLevel(Level.INFO); + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setLevel(Level.INFO); + logger.addHandler(consoleHandler); + } + + private TypeSolver typeSolver; + private JavaParserFacade facade; + + public TypeExtractor(TypeSolver typeSolver, JavaParserFacade facade) { + this.typeSolver = typeSolver; + this.facade = facade; + } + + @Override + public ResolvedType visit(VariableDeclarator node, Boolean solveLambdas) { + if (requireParentNode(node) instanceof FieldDeclaration) { + return facade.convertToUsageVariableType(node); + } else if (requireParentNode(node) instanceof VariableDeclarationExpr) { + return facade.convertToUsageVariableType(node); + } + throw new UnsupportedOperationException(requireParentNode(node).getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(Parameter node, Boolean solveLambdas) { + if (node.getType() instanceof UnknownType) { + throw new IllegalStateException("Parameter has unknown type: " + node); + } + return facade.convertToUsage(node.getType(), node); + } + + + @Override + public ResolvedType visit(ArrayAccessExpr node, Boolean solveLambdas) { + ResolvedType arrayUsageType = node.getName().accept(this, solveLambdas); + if (arrayUsageType.isArray()) { + return ((ResolvedArrayType) arrayUsageType).getComponentType(); + } + return arrayUsageType; + } + + @Override + public ResolvedType visit(ArrayCreationExpr node, Boolean solveLambdas) { + ResolvedType res = facade.convertToUsage(node.getElementType(), JavaParserFactory.getContext(node, typeSolver)); + for (int i = 0; i < node.getLevels().size(); i++) { + res = new ResolvedArrayType(res); + } + return res; + } + + @Override + public ResolvedType visit(ArrayInitializerExpr node, Boolean solveLambdas) { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + + @Override + public ResolvedType visit(AssignExpr node, Boolean solveLambdas) { + return node.getTarget().accept(this, solveLambdas); + } + + @Override + public ResolvedType visit(BinaryExpr node, Boolean solveLambdas) { + switch (node.getOperator()) { + case PLUS: + case MINUS: + case DIVIDE: + case MULTIPLY: + return facade.getBinaryTypeConcrete(node.getLeft(), node.getRight(), solveLambdas); + case LESS_EQUALS: + case LESS: + case GREATER: + case GREATER_EQUALS: + case EQUALS: + case NOT_EQUALS: + case OR: + case AND: + return ResolvedPrimitiveType.BOOLEAN; + case BINARY_AND: + case BINARY_OR: + case SIGNED_RIGHT_SHIFT: + case UNSIGNED_RIGHT_SHIFT: + case LEFT_SHIFT: + case REMAINDER: + case XOR: + return node.getLeft().accept(this, solveLambdas); + default: + throw new UnsupportedOperationException("Operator " + node.getOperator().name()); + } + } + + @Override + public ResolvedType visit(CastExpr node, Boolean solveLambdas) { + return facade.convertToUsage(node.getType(), JavaParserFactory.getContext(node, typeSolver)); + } + + @Override + public ResolvedType visit(ClassExpr node, Boolean solveLambdas) { + // This implementation does not regard the actual type argument of the ClassExpr. + com.github.javaparser.ast.type.Type astType = node.getType(); + ResolvedType jssType = facade.convertToUsage(astType, node.getType()); + return new ReferenceTypeImpl(new ReflectionClassDeclaration(Class.class, typeSolver), ImmutableList.of(jssType), typeSolver); + } + + @Override + public ResolvedType visit(ConditionalExpr node, Boolean solveLambdas) { + return node.getThenExpr().accept(this, solveLambdas); + } + + @Override + public ResolvedType visit(EnclosedExpr node, Boolean solveLambdas) { + return node.getInner().accept(this, solveLambdas); + } + + /** + * Java Parser can't differentiate between packages, internal types, and fields. + * All three are lumped together into FieldAccessExpr. We need to differentiate them. + */ + private ResolvedType solveDotExpressionType(ResolvedReferenceTypeDeclaration parentType, FieldAccessExpr node) { + // Fields and internal type declarations cannot have the same name. + // Thus, these checks will always be mutually exclusive. + if (parentType.hasField(node.getName().getId())) { + return parentType.getField(node.getName().getId()).getType(); + } else if (parentType.hasInternalType(node.getName().getId())) { + return new ReferenceTypeImpl(parentType.getInternalType(node.getName().getId()), typeSolver); + } else { + throw new UnsolvedSymbolException(node.getName().getId()); + } + } + + @Override + public ResolvedType visit(FieldAccessExpr node, Boolean solveLambdas) { + // We should understand if this is a static access + if (node.getScope() instanceof NameExpr || + node.getScope() instanceof FieldAccessExpr) { + Expression staticValue = node.getScope(); + SymbolReference<ResolvedTypeDeclaration> typeAccessedStatically = JavaParserFactory.getContext(node, typeSolver).solveType(staticValue.toString(), typeSolver); + if (typeAccessedStatically.isSolved()) { + // TODO here maybe we have to substitute type typeParametersValues + return solveDotExpressionType( + typeAccessedStatically.getCorrespondingDeclaration().asReferenceType(), node); + } + } else if (node.getScope() instanceof ThisExpr) { + // If we are accessing through a 'this' expression, first resolve the type + // corresponding to 'this' + SymbolReference<ResolvedTypeDeclaration> solve = facade.solve((ThisExpr) node.getScope()); + // If found get it's declaration and get the field in there + if (solve.isSolved()) { + ResolvedTypeDeclaration correspondingDeclaration = solve.getCorrespondingDeclaration(); + if (correspondingDeclaration instanceof ResolvedReferenceTypeDeclaration) { + return solveDotExpressionType(correspondingDeclaration.asReferenceType(), node); + } + } + + } else if (node.getScope().toString().indexOf('.') > 0) { + // try to find fully qualified name + SymbolReference<ResolvedReferenceTypeDeclaration> sr = typeSolver.tryToSolveType(node.getScope().toString()); + if (sr.isSolved()) { + return solveDotExpressionType(sr.getCorrespondingDeclaration(), node); + } + } + Optional<Value> value = Optional.empty(); + try { + value = new SymbolSolver(typeSolver).solveSymbolAsValue(node.getName().getId(), node); + } catch (com.github.javaparser.resolution.UnsolvedSymbolException use) { + // This node may have a package name as part of its fully qualified name. + // We should solve for the type declaration inside this package. + SymbolReference<ResolvedReferenceTypeDeclaration> sref = typeSolver.tryToSolveType(node.toString()); + if (sref.isSolved()) { + return new ReferenceTypeImpl(sref.getCorrespondingDeclaration(), typeSolver); + } + } + if (value.isPresent()) { + return value.get().getType(); + } + throw new com.github.javaparser.resolution.UnsolvedSymbolException(node.getName().getId()); + } + + @Override + public ResolvedType visit(InstanceOfExpr node, Boolean solveLambdas) { + return ResolvedPrimitiveType.BOOLEAN; + } + + @Override + public ResolvedType visit(StringLiteralExpr node, Boolean solveLambdas) { + return new ReferenceTypeImpl(new ReflectionTypeSolver().solveType(String.class.getCanonicalName()), typeSolver); + } + + @Override + public ResolvedType visit(IntegerLiteralExpr node, Boolean solveLambdas) { + return ResolvedPrimitiveType.INT; + } + + @Override + public ResolvedType visit(LongLiteralExpr node, Boolean solveLambdas) { + return ResolvedPrimitiveType.LONG; + } + + @Override + public ResolvedType visit(CharLiteralExpr node, Boolean solveLambdas) { + return ResolvedPrimitiveType.CHAR; + } + + @Override + public ResolvedType visit(DoubleLiteralExpr node, Boolean solveLambdas) { + if (node.getValue().toLowerCase().endsWith("f")) { + return ResolvedPrimitiveType.FLOAT; + } + return ResolvedPrimitiveType.DOUBLE; + } + + @Override + public ResolvedType visit(BooleanLiteralExpr node, Boolean solveLambdas) { + return ResolvedPrimitiveType.BOOLEAN; + } + + @Override + public ResolvedType visit(NullLiteralExpr node, Boolean solveLambdas) { + return NullType.INSTANCE; + } + + @Override + public ResolvedType visit(MethodCallExpr node, Boolean solveLambdas) { + logger.finest("getType on method call " + node); + // first solve the method + MethodUsage ref = facade.solveMethodAsUsage(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 + } + + @Override + public ResolvedType visit(NameExpr node, Boolean solveLambdas) { + logger.finest("getType on name expr " + node); + Optional<Value> value = new SymbolSolver(typeSolver).solveSymbolAsValue(node.getName().getId(), node); + if (!value.isPresent()) { + throw new com.github.javaparser.resolution.UnsolvedSymbolException("Solving " + node, node.getName().getId()); + } else { + return value.get().getType(); + } + } + + @Override + public ResolvedType visit(ObjectCreationExpr node, Boolean solveLambdas) { + return facade.convertToUsage(node.getType(), node); + } + + @Override + public ResolvedType visit(ThisExpr node, Boolean solveLambdas) { + // 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 new ReferenceTypeImpl(clazz.getCorrespondingDeclaration(), typeSolver); + } + // 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 new ReferenceTypeImpl(facade.getTypeDeclaration(classByName.get()), typeSolver); + } + } + + } + return new ReferenceTypeImpl(facade.getTypeDeclaration(facade.findContainingTypeDeclOrObjectCreationExpr(node)), typeSolver); + } + + @Override + public ResolvedType visit(SuperExpr node, Boolean solveLambdas) { + ResolvedTypeDeclaration typeOfNode = facade.getTypeDeclaration(facade.findContainingTypeDecl(node)); + if (typeOfNode instanceof ResolvedClassDeclaration) { + return ((ResolvedClassDeclaration) typeOfNode).getSuperClass(); + } else { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + } + + @Override + public ResolvedType visit(UnaryExpr node, Boolean solveLambdas) { + switch (node.getOperator()) { + case MINUS: + case PLUS: + return node.getExpression().accept(this, solveLambdas); + case LOGICAL_COMPLEMENT: + return ResolvedPrimitiveType.BOOLEAN; + case POSTFIX_DECREMENT: + case PREFIX_DECREMENT: + case POSTFIX_INCREMENT: + case PREFIX_INCREMENT: + return node.getExpression().accept(this, solveLambdas); + default: + throw new UnsupportedOperationException(node.getOperator().name()); + } + } + + @Override + public ResolvedType visit(VariableDeclarationExpr node, Boolean solveLambdas) { + if (node.getVariables().size() != 1) { + throw new UnsupportedOperationException(); + } + return facade.convertToUsageVariableType(node.getVariables().get(0)); + } + + + @Override + public ResolvedType visit(LambdaExpr node, Boolean solveLambdas) { + if (requireParentNode(node) instanceof MethodCallExpr) { + MethodCallExpr callExpr = (MethodCallExpr) requireParentNode(node); + int pos = JavaParserSymbolDeclaration.getParamPos(node); + SymbolReference<ResolvedMethodDeclaration> refMethod = facade.solve(callExpr); + if (!refMethod.isSolved()) { + throw new com.github.javaparser.resolution.UnsolvedSymbolException(requireParentNode(node).toString(), callExpr.getName().getId()); + } + logger.finest("getType on lambda expr " + refMethod.getCorrespondingDeclaration().getName()); + if (solveLambdas) { + + // The type parameter referred here should be the java.util.stream.Stream.T + ResolvedType result = refMethod.getCorrespondingDeclaration().getParam(pos).getType(); + + if (callExpr.getScope().isPresent()) { + Expression scope = callExpr.getScope().get(); + + // If it is a static call we should not try to get the type of the scope + boolean staticCall = false; + if (scope instanceof NameExpr) { + NameExpr nameExpr = (NameExpr) scope; + try { + SymbolReference<ResolvedTypeDeclaration> type = JavaParserFactory.getContext(nameExpr, typeSolver).solveType(nameExpr.getName().getId(), typeSolver); + if (type.isSolved()) { + staticCall = true; + } + } catch (Exception e) { + + } + } + + if (!staticCall) { + ResolvedType scopeType = facade.getType(scope); + if (scopeType.isReferenceType()) { + result = scopeType.asReferenceType().useThisTypeParametersOnTheGivenType(result); + } + } + } + + // 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<MethodUsage> functionalMethod = FunctionalInterfaceLogic.getFunctionalMethod(result); + if (functionalMethod.isPresent()) { + LambdaExpr lambdaExpr = node; + + InferenceContext lambdaCtx = new InferenceContext(MyObjectProvider.INSTANCE); + InferenceContext funcInterfaceCtx = new InferenceContext(MyObjectProvider.INSTANCE); + + // At this point parameterType + // if Function<T=? super Stream.T, ? extends map.R> + // we should replace Stream.T + ResolvedType functionalInterfaceType = ReferenceTypeImpl.undeterminedParameters(functionalMethod.get().getDeclaration().declaringType(), typeSolver); + + lambdaCtx.addPair(result, functionalInterfaceType); + + ResolvedType actualType; + + if (lambdaExpr.getBody() instanceof ExpressionStmt) { + actualType = facade.getType(((ExpressionStmt) lambdaExpr.getBody()).getExpression()); + } else if (lambdaExpr.getBody() instanceof BlockStmt) { + BlockStmt blockStmt = (BlockStmt) lambdaExpr.getBody(); + + // Get all the return statements in the lambda block + List<ReturnStmt> returnStmts = blockStmt.findAll(ReturnStmt.class); + + if (returnStmts.size() > 0) { + actualType = returnStmts.stream() + .map(returnStmt -> returnStmt.getExpression().map(e -> facade.getType(e)).orElse(ResolvedVoidType.INSTANCE)) + .filter(x -> x != null && !x.isVoid() && !x.isNull()) + .findFirst() + .orElse(ResolvedVoidType.INSTANCE); + + } else { + return ResolvedVoidType.INSTANCE; + } + + + } else { + throw new UnsupportedOperationException(); + } + + ResolvedType formalType = functionalMethod.get().returnType(); + + // Infer the functional interfaces' return vs actual type + funcInterfaceCtx.addPair(formalType, actualType); + // Substitute to obtain a new type + ResolvedType functionalTypeWithReturn = funcInterfaceCtx.resolve(funcInterfaceCtx.addSingle(functionalInterfaceType)); + + // if the functional method returns void anyway + // we don't need to bother inferring types + if (!(formalType instanceof ResolvedVoidType)) { + lambdaCtx.addPair(result, functionalTypeWithReturn); + result = lambdaCtx.resolve(lambdaCtx.addSingle(result)); + } + } + + 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"); + } + } + + @Override + public ResolvedType visit(MethodReferenceExpr node, Boolean solveLambdas) { + if (requireParentNode(node) instanceof MethodCallExpr) { + MethodCallExpr callExpr = (MethodCallExpr) requireParentNode(node); + int pos = JavaParserSymbolDeclaration.getParamPos(node); + SymbolReference<ResolvedMethodDeclaration> refMethod = facade.solve(callExpr, false); + if (!refMethod.isSolved()) { + throw new com.github.javaparser.resolution.UnsolvedSymbolException(requireParentNode(node).toString(), callExpr.getName().getId()); + } + logger.finest("getType on method reference expr " + refMethod.getCorrespondingDeclaration().getName()); + //logger.finest("Method param " + refMethod.getCorrespondingDeclaration().getParam(pos)); + if (solveLambdas) { + MethodUsage usage = facade.solveMethodAsUsage(callExpr); + ResolvedType result = usage.getParamType(pos); + // 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 + if (FunctionalInterfaceLogic.getFunctionalMethod(result).isPresent()) { + MethodReferenceExpr methodReferenceExpr = node; + + ResolvedType actualType = facade.toMethodUsage(methodReferenceExpr).returnType(); + ResolvedType formalType = FunctionalInterfaceLogic.getFunctionalMethod(result).get().returnType(); + + InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE); + inferenceContext.addPair(formalType, actualType); + result = inferenceContext.resolve(inferenceContext.addSingle(result)); + } + + return result; + } + return refMethod.getCorrespondingDeclaration().getParam(pos).getType(); + } + throw new UnsupportedOperationException("The type of a method reference expr depends on the position and its return value"); + } + + @Override + public ResolvedType visit(FieldDeclaration node, Boolean solveLambdas) { + if (node.getVariables().size() == 1) { + return node.getVariables().get(0).accept(this, solveLambdas); + } + throw new IllegalArgumentException("Cannot resolve the type of a field with multiple variable declarations. Pick one"); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/UnsolvedSymbolException.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/UnsolvedSymbolException.java new file mode 100644 index 000000000..f7ab7d11e --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/UnsolvedSymbolException.java @@ -0,0 +1,71 @@ +/* + * 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.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +/** + * @author Federico Tomassetti + * + * @deprecated Use {@link com.github.javaparser.resolution.UnsolvedSymbolException} instead + */ +// Use the one in model instead +@Deprecated +public class UnsolvedSymbolException extends RuntimeException { + + private String context; + private String name; + private TypeSolver typeSolver; + + @Deprecated + public UnsolvedSymbolException(String name, TypeSolver typeSolver) { + super("Unsolved symbol : " + name + " using typesolver " + typeSolver); + this.typeSolver = typeSolver; + this.name = name; + } + + @Deprecated + public UnsolvedSymbolException(Context context, String name) { + super("Unsolved symbol in " + context + " : " + name); + this.context = context.toString(); + this.name = name; + } + + @Deprecated + public UnsolvedSymbolException(String context, String name) { + super("Unsolved symbol in " + context + " : " + name); + this.context = context; + this.name = name; + } + + @Deprecated + public UnsolvedSymbolException(String name) { + super("Unsolved symbol : " + name); + this.context = "unknown"; + this.name = name; + } + + @Override + public String toString() { + return "UnsolvedSymbolException{" + + "context='" + context + '\'' + + ", name='" + name + '\'' + + ", typeSolver=" + typeSolver + + '}'; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AbstractJavaParserContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AbstractJavaParserContext.java new file mode 100644 index 000000000..cc008a527 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AbstractJavaParserContext.java @@ -0,0 +1,193 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import java.util.*; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; +import static java.util.Collections.*; + +/** + * @author Federico Tomassetti + */ +public abstract class AbstractJavaParserContext<N extends Node> implements Context { + + protected N wrappedNode; + protected TypeSolver typeSolver; + + /// + /// Static methods + /// + + public static SymbolReference<ResolvedValueDeclaration> solveWith(SymbolDeclarator symbolDeclarator, String name) { + for (ResolvedValueDeclaration decl : symbolDeclarator.getSymbolDeclarations()) { + if (decl.getName().equals(name)) { + return SymbolReference.solved(decl); + } + } + return SymbolReference.unsolved(ResolvedValueDeclaration.class); + } + + /// + /// Constructors + /// + + public AbstractJavaParserContext(N wrappedNode, TypeSolver typeSolver) { + if (wrappedNode == null) { + throw new NullPointerException(); + } + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + /// + /// Public methods + /// + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AbstractJavaParserContext<?> that = (AbstractJavaParserContext<?>) o; + + if (wrappedNode != null ? !wrappedNode.equals(that.wrappedNode) : that.wrappedNode != null) return false; + + return true; + } + + @Override + public int hashCode() { + return wrappedNode != null ? wrappedNode.hashCode() : 0; + } + + @Override + public Optional<ResolvedType> solveGenericType(String name, TypeSolver typeSolver) { + Context parent = getParent(); + if (parent == null) { + return Optional.empty(); + } else { + return parent.solveGenericType(name, typeSolver); + } + } + + @Override + public final Context getParent() { + Node parent = wrappedNode.getParentNode().orElse(null); + if (parent instanceof MethodCallExpr) { + MethodCallExpr parentCall = (MethodCallExpr) parent; + boolean found = false; + if (parentCall.getArguments() != null) { + for (Expression expression : parentCall.getArguments()) { + if (expression == wrappedNode) { + found = true; + } + } + } + if (found) { + Node notMethod = parent; + while (notMethod instanceof MethodCallExpr) { + notMethod = requireParentNode(notMethod); + } + return JavaParserFactory.getContext(notMethod, typeSolver); + } + } + Node notMethod = parent; + while (notMethod instanceof MethodCallExpr || notMethod instanceof FieldAccessExpr) { + notMethod = notMethod.getParentNode().orElse(null); + } + if (notMethod == null) { + return null; + } + return JavaParserFactory.getContext(notMethod, typeSolver); + } + + /// + /// Protected methods + /// + + protected Optional<Value> solveWithAsValue(SymbolDeclarator symbolDeclarator, String name, TypeSolver typeSolver) { + return symbolDeclarator.getSymbolDeclarations().stream() + .filter(d -> d.getName().equals(name)) + .map(Value::from) + .findFirst(); + } + + protected Collection<ResolvedReferenceTypeDeclaration> findTypeDeclarations(Optional<Expression> optScope, TypeSolver typeSolver) { + if (optScope.isPresent()) { + Expression scope = optScope.get(); + + // consider static methods + if (scope instanceof NameExpr) { + NameExpr scopeAsName = (NameExpr) scope; + SymbolReference<ResolvedTypeDeclaration> symbolReference = this.solveType(scopeAsName.getName().getId(), typeSolver); + if (symbolReference.isSolved() && symbolReference.getCorrespondingDeclaration().isType()) { + return singletonList(symbolReference.getCorrespondingDeclaration().asReferenceType()); + } + } + + ResolvedType typeOfScope; + try { + typeOfScope = JavaParserFacade.get(typeSolver).getType(scope); + } catch (Exception e) { + throw new RuntimeException("Issue calculating the type of the scope of " + this, e); + } + if (typeOfScope.isWildcard()) { + if (typeOfScope.asWildcard().isExtends() || typeOfScope.asWildcard().isSuper()) { + return singletonList(typeOfScope.asWildcard().getBoundedType().asReferenceType().getTypeDeclaration()); + } else { + return singletonList(new ReflectionClassDeclaration(Object.class, typeSolver).asReferenceType()); + } + } else if (typeOfScope.isArray()) { + // method call on array are Object methods + return singletonList(new ReflectionClassDeclaration(Object.class, typeSolver).asReferenceType()); + } else if (typeOfScope.isTypeVariable()) { + Collection<ResolvedReferenceTypeDeclaration> result = new ArrayList<>(); + for (ResolvedTypeParameterDeclaration.Bound bound : typeOfScope.asTypeParameter().getBounds()) { + result.add(bound.getType().asReferenceType().getTypeDeclaration()); + } + return result; + } else if (typeOfScope.isConstraint()) { + return singletonList(typeOfScope.asConstraintType().getBound().asReferenceType().getTypeDeclaration()); + } + return singletonList(typeOfScope.asReferenceType().getTypeDeclaration()); + } + ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode); + return singletonList(typeOfScope.asReferenceType().getTypeDeclaration()); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AbstractMethodLikeDeclarationContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AbstractMethodLikeDeclarationContext.java new file mode 100644 index 000000000..d611d71a5 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AbstractMethodLikeDeclarationContext.java @@ -0,0 +1,101 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.contexts; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.nodeTypes.NodeWithParameters; +import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.resolution.types.ResolvedTypeVariable; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import java.util.List; +import java.util.Optional; + +/** + * @author Federico Tomassetti + */ +public abstract class AbstractMethodLikeDeclarationContext + <T extends Node & NodeWithParameters<T> & NodeWithTypeParameters<T>> extends AbstractJavaParserContext<T> { + + public AbstractMethodLikeDeclarationContext(T wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + public final SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + for (Parameter parameter : wrappedNode.getParameters()) { + SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(parameter, typeSolver); + SymbolReference<? extends ResolvedValueDeclaration> symbolReference = AbstractJavaParserContext.solveWith(sb, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public final Optional<ResolvedType> solveGenericType(String name, TypeSolver typeSolver) { + for (com.github.javaparser.ast.type.TypeParameter tp : wrappedNode.getTypeParameters()) { + if (tp.getName().getId().equals(name)) { + return Optional.of(new ResolvedTypeVariable(new JavaParserTypeParameter(tp, typeSolver))); + } + } + return super.solveGenericType(name, typeSolver); + } + + @Override + public final Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + for (Parameter parameter : wrappedNode.getParameters()) { + SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(parameter, typeSolver); + Optional<Value> symbolReference = solveWithAsValue(sb, name, typeSolver); + if (symbolReference.isPresent()) { + // Perform parameter type substitution as needed + return symbolReference; + } + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbolAsValue(name, typeSolver); + } + + @Override + public final SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (wrappedNode.getTypeParameters() != null) { + for (com.github.javaparser.ast.type.TypeParameter tp : wrappedNode.getTypeParameters()) { + if (tp.getName().getId().equals(name)) { + return SymbolReference.solved(new JavaParserTypeParameter(tp, typeSolver)); + } + } + } + + // Local types + List<com.github.javaparser.ast.body.TypeDeclaration> localTypes = wrappedNode.findAll( + com.github.javaparser.ast.body.TypeDeclaration.class); + for (com.github.javaparser.ast.body.TypeDeclaration<?> localType : localTypes) { + if (localType.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(localType)); + } else if (name.startsWith(String.format("%s.", localType.getName()))) { + return JavaParserFactory.getContext(localType, typeSolver).solveType( + name.substring(localType.getName().getId().length() + 1), typeSolver); + } + } + + return getParent().solveType(name, typeSolver); + } + + @Override + public final SymbolReference<ResolvedMethodDeclaration> solveMethod( + String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AnonymousClassDeclarationContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AnonymousClassDeclarationContext.java new file mode 100644 index 000000000..48133596a --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/AnonymousClassDeclarationContext.java @@ -0,0 +1,186 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.contexts; + +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.nodeTypes.NodeWithTypeArguments; +import com.github.javaparser.ast.type.TypeParameter; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations + .JavaParserAnonymousClassDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; +import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; +import com.google.common.base.Preconditions; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * A symbol resolution context for an object creation node. + */ +public class AnonymousClassDeclarationContext extends AbstractJavaParserContext<ObjectCreationExpr> { + + private final JavaParserAnonymousClassDeclaration myDeclaration = + new JavaParserAnonymousClassDeclaration(wrappedNode, typeSolver); + + public AnonymousClassDeclarationContext(ObjectCreationExpr node, TypeSolver typeSolver) { + super(node, typeSolver); + Preconditions.checkArgument(node.getAnonymousClassBody().isPresent(), + "An anonymous class must have a body"); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, + List<ResolvedType> argumentsTypes, + boolean staticOnly, + TypeSolver typeSolver) { + List<ResolvedMethodDeclaration> candidateMethods = + myDeclaration + .getDeclaredMethods() + .stream() + .filter(m -> m.getName().equals(name) && (!staticOnly || m.isStatic())) + .collect(Collectors.toList()); + + if (!Object.class.getCanonicalName().equals(myDeclaration.getQualifiedName())) { + for (ResolvedReferenceType ancestor : myDeclaration.getAncestors()) { + SymbolReference<ResolvedMethodDeclaration> res = + MethodResolutionLogic.solveMethodInType(ancestor.getTypeDeclaration(), + name, + argumentsTypes, + staticOnly, + typeSolver); + // consider methods from superclasses and only default methods from interfaces : + // not true, we should keep abstract as a valid candidate + // abstract are removed in MethodResolutionLogic.isApplicable is necessary + if (res.isSolved()) { + candidateMethods.add(res.getCorrespondingDeclaration()); + } + } + } + + // We want to avoid infinite recursion when a class is using its own method + // see issue #75 + if (candidateMethods.isEmpty()) { + SymbolReference<ResolvedMethodDeclaration> parentSolution = + getParent().solveMethod(name, argumentsTypes, staticOnly, typeSolver); + if (parentSolution.isSolved()) { + candidateMethods.add(parentSolution.getCorrespondingDeclaration()); + } + } + + // if is interface and candidate method list is empty, we should check the Object Methods + if (candidateMethods.isEmpty() && myDeclaration.getSuperTypeDeclaration().isInterface()) { + SymbolReference<ResolvedMethodDeclaration> res = + MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, + typeSolver), + name, + argumentsTypes, + false, + typeSolver); + if (res.isSolved()) { + candidateMethods.add(res.getCorrespondingDeclaration()); + } + } + + return MethodResolutionLogic.findMostApplicable(candidateMethods, + name, + argumentsTypes, + typeSolver); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + List<com.github.javaparser.ast.body.TypeDeclaration> typeDeclarations = + myDeclaration + .findMembersOfKind(com.github.javaparser.ast.body.TypeDeclaration.class); + + Optional<SymbolReference<ResolvedTypeDeclaration>> exactMatch = + typeDeclarations + .stream() + .filter(internalType -> internalType.getName().getId().equals(name)) + .findFirst() + .map(internalType -> + SymbolReference.solved( + JavaParserFacade.get(typeSolver).getTypeDeclaration(internalType))); + + if(exactMatch.isPresent()){ + return exactMatch.get(); + } + + Optional<SymbolReference<ResolvedTypeDeclaration>> recursiveMatch = + typeDeclarations + .stream() + .filter(internalType -> name.startsWith(String.format("%s.", internalType.getName()))) + .findFirst() + .map(internalType -> + JavaParserFactory + .getContext(internalType, typeSolver) + .solveType(name.substring(internalType.getName().getId().length() + 1), + typeSolver)); + + if (recursiveMatch.isPresent()) { + return recursiveMatch.get(); + } + + Optional<SymbolReference<ResolvedTypeDeclaration>> typeArgumentsMatch = + wrappedNode + .getTypeArguments() + .map(nodes -> + ((NodeWithTypeArguments<?>) nodes).getTypeArguments() + .orElse(new NodeList<>())) + .orElse(new NodeList<>()) + .stream() + .filter(type -> type.toString().equals(name)) + .findFirst() + .map(matchingType -> + SymbolReference.solved( + new JavaParserTypeParameter(new TypeParameter(matchingType.toString()), + typeSolver))); + + if (typeArgumentsMatch.isPresent()) { + return typeArgumentsMatch.get(); + } + + // Look into extended classes and implemented interfaces + for (ResolvedReferenceType ancestor : myDeclaration.getAncestors()) { + // look at names of extended classes and implemented interfaces (this may not be important because they are checked in CompilationUnitContext) + if (ancestor.getTypeDeclaration().getName().equals(name)) { + return SymbolReference.solved(ancestor.getTypeDeclaration()); + } + // look into internal types of extended classes and implemented interfaces + try { + for (ResolvedTypeDeclaration internalTypeDeclaration : ancestor.getTypeDeclaration().internalTypes()) { + if (internalTypeDeclaration.getName().equals(name)) { + return SymbolReference.solved(internalTypeDeclaration); + } + } + } catch (UnsupportedOperationException e) { + // just continue using the next ancestor + } + } + + return getParent().solveType(name, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, + TypeSolver typeSolver) { + Preconditions.checkArgument(typeSolver != null); + + if (myDeclaration.hasVisibleField(name)) { + return SymbolReference.solved(myDeclaration.getVisibleField(name)); + } + + return getParent().solveSymbol(name, typeSolver); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/CatchClauseContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/CatchClauseContext.java new file mode 100644 index 000000000..4683f272a --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/CatchClauseContext.java @@ -0,0 +1,54 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.contexts; + +import com.github.javaparser.ast.stmt.CatchClause; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import java.util.List; +import java.util.Optional; + +/** + * @author Fred Lefévère-Laoide + */ +public class CatchClauseContext extends AbstractJavaParserContext<CatchClause> { + + public CatchClauseContext(CatchClause wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + public final SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(wrappedNode.getParameter(), typeSolver); + SymbolReference<? extends ResolvedValueDeclaration> symbolReference = AbstractJavaParserContext.solveWith(sb, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public final Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(wrappedNode.getParameter(), typeSolver); + Optional<Value> symbolReference = solveWithAsValue(sb, name, typeSolver); + if (symbolReference.isPresent()) { + // Perform parameter type substitution as needed + return symbolReference; + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbolAsValue(name, typeSolver); + } + + @Override + public final SymbolReference<ResolvedMethodDeclaration> solveMethod( + String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ClassOrInterfaceDeclarationContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ClassOrInterfaceDeclarationContext.java new file mode 100644 index 000000000..01f4b050c --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ClassOrInterfaceDeclarationContext.java @@ -0,0 +1,109 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.resolution.types.ResolvedTypeVariable; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; + +import java.util.List; +import java.util.Optional; + +/** + * @author Federico Tomassetti + */ +public class ClassOrInterfaceDeclarationContext extends AbstractJavaParserContext<ClassOrInterfaceDeclaration> { + + private JavaParserTypeDeclarationAdapter javaParserTypeDeclarationAdapter; + + /// + /// Constructors + /// + + public ClassOrInterfaceDeclarationContext(ClassOrInterfaceDeclaration wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + this.javaParserTypeDeclarationAdapter = new JavaParserTypeDeclarationAdapter(wrappedNode, typeSolver, + getDeclaration(), this); + } + + /// + /// Public methods + /// + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + if (typeSolver == null) throw new IllegalArgumentException(); + + if (this.getDeclaration().hasVisibleField(name)) { + return SymbolReference.solved(this.getDeclaration().getVisibleField(name)); + } + + // then to parent + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + if (typeSolver == null) throw new IllegalArgumentException(); + + if (this.getDeclaration().hasVisibleField(name)) { + return Optional.of(Value.from(this.getDeclaration().getVisibleField(name))); + } + + // then to parent + return getParent().solveSymbolAsValue(name, typeSolver); + } + + @Override + public Optional<ResolvedType> solveGenericType(String name, TypeSolver typeSolver) { + for (com.github.javaparser.ast.type.TypeParameter tp : wrappedNode.getTypeParameters()) { + if (tp.getName().getId().equals(name)) { + return Optional.of(new ResolvedTypeVariable(new JavaParserTypeParameter(tp, typeSolver))); + } + } + return getParent().solveGenericType(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + return javaParserTypeDeclarationAdapter.solveType(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return javaParserTypeDeclarationAdapter.solveMethod(name, argumentsTypes, staticOnly, typeSolver); + } + + public SymbolReference<ResolvedConstructorDeclaration> solveConstructor(List<ResolvedType> argumentsTypes, TypeSolver typeSolver) { + return javaParserTypeDeclarationAdapter.solveConstructor(argumentsTypes, typeSolver); + } + + /// + /// Private methods + /// + + private ResolvedReferenceTypeDeclaration getDeclaration() { + return JavaParserFacade.get(typeSolver).getTypeDeclaration(this.wrappedNode); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/CompilationUnitContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/CompilationUnitContext.java new file mode 100644 index 000000000..e6a4aa0d5 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/CompilationUnitContext.java @@ -0,0 +1,291 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.ImportDeclaration; +import com.github.javaparser.ast.body.AnnotationDeclaration; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.EnumDeclaration; +import com.github.javaparser.ast.body.TypeDeclaration; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.Name; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnnotationDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; + +import java.util.List; + +/** + * @author Federico Tomassetti + */ +public class CompilationUnitContext extends AbstractJavaParserContext<CompilationUnit> { + + /// + /// Static methods + /// + + private static boolean isQualifiedName(String name) { + return name.contains("."); + } + + /// + /// Constructors + /// + + public CompilationUnitContext(CompilationUnit wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + /// + /// Public methods + /// + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + + // solve absolute references + String itName = name; + while (itName.contains(".")) { + String typeName = getType(itName); + String memberName = getMember(itName); + SymbolReference<ResolvedTypeDeclaration> type = this.solveType(typeName, typeSolver); + if (type.isSolved()) { + return new SymbolSolver(typeSolver).solveSymbolInType(type.getCorrespondingDeclaration(), memberName); + } else { + itName = typeName; + } + } + + // Look among statically imported values + if (wrappedNode.getImports() != null) { + for (ImportDeclaration importDecl : wrappedNode.getImports()) { + if(importDecl.isStatic()){ + if(importDecl.isAsterisk()) { + String qName = importDecl.getNameAsString(); + ResolvedTypeDeclaration importedType = typeSolver.solveType(qName); + SymbolReference<? extends ResolvedValueDeclaration> ref = new SymbolSolver(typeSolver).solveSymbolInType(importedType, name); + if (ref.isSolved()) { + return ref; + } + } else{ + String whole = importDecl.getNameAsString(); + + // split in field/method name and type name + String memberName = getMember(whole); + String typeName = getType(whole); + + if (memberName.equals(name)) { + ResolvedTypeDeclaration importedType = typeSolver.solveType(typeName); + return new SymbolSolver(typeSolver).solveSymbolInType(importedType, memberName); + } + } + } + } + } + + return SymbolReference.unsolved(ResolvedValueDeclaration.class); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (wrappedNode.getTypes() != null) { + for (TypeDeclaration<?> type : wrappedNode.getTypes()) { + if (type.getName().getId().equals(name)) { + if (type instanceof ClassOrInterfaceDeclaration) { + return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration((ClassOrInterfaceDeclaration) type)); + } else if (type instanceof AnnotationDeclaration) { + return SymbolReference.solved(new JavaParserAnnotationDeclaration((AnnotationDeclaration) type, typeSolver)); + } else if (type instanceof EnumDeclaration) { + return SymbolReference.solved(new JavaParserEnumDeclaration((EnumDeclaration) type, typeSolver)); + } else { + throw new UnsupportedOperationException(type.getClass().getCanonicalName()); + } + } + } + } + + if (wrappedNode.getImports() != null) { + int dotPos = name.indexOf('.'); + String prefix = null; + if (dotPos > -1) { + prefix = name.substring(0, dotPos); + } + // look into type imports + for (ImportDeclaration importDecl : wrappedNode.getImports()) { + if (!importDecl.isAsterisk()) { + String qName = importDecl.getNameAsString(); + boolean defaultPackage = !importDecl.getName().getQualifier().isPresent(); + boolean found = !defaultPackage && importDecl.getName().getIdentifier().equals(name); + if (!found) { + if (prefix != null) { + found = qName.endsWith("." + prefix); + if (found) { + qName = qName + name.substring(dotPos); + } + } + } + if (found) { + SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); + if (ref.isSolved()) { + return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); + } + } + } + } + // look into type imports on demand + for (ImportDeclaration importDecl : wrappedNode.getImports()) { + if (importDecl.isAsterisk()) { + String qName = importDecl.getNameAsString() + "." + name; + SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); + if (ref.isSolved()) { + return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); + } + } + } + } + + // Look in current package + if (this.wrappedNode.getPackageDeclaration().isPresent()) { + String qName = this.wrappedNode.getPackageDeclaration().get().getName().toString() + "." + name; + SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); + if (ref.isSolved()) { + return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); + } + } else { + // look for classes in the default package + String qName = name; + SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); + if (ref.isSolved()) { + return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); + } + } + + // Look in the java.lang package + SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType("java.lang." + name); + if (ref.isSolved()) { + return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); + } + + // DO NOT look for absolute name if this name is not qualified: you cannot import classes from the default package + if (isQualifiedName(name)) { + return SymbolReference.adapt(typeSolver.tryToSolveType(name), ResolvedTypeDeclaration.class); + } else { + return SymbolReference.unsolved(ResolvedReferenceTypeDeclaration.class); + } + } + + private String qName(ClassOrInterfaceType type) { + if (type.getScope().isPresent()) { + return qName(type.getScope().get()) + "." + type.getName().getId(); + } else { + return type.getName().getId(); + } + } + + private String qName(Name name) { + if (name.getQualifier().isPresent()) { + return qName(name.getQualifier().get()) + "." + name.getId(); + } else { + return name.getId(); + } + } + + private String toSimpleName(String qName) { + String[] parts = qName.split("\\."); + return parts[parts.length - 1]; + } + + private String packageName(String qName) { + int lastDot = qName.lastIndexOf('.'); + if (lastDot == -1) { + throw new UnsupportedOperationException(); + } else { + return qName.substring(0, lastDot); + } + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + for (ImportDeclaration importDecl : wrappedNode.getImports()) { + if(importDecl.isStatic()){ + if(importDecl.isAsterisk()){ + String importString = importDecl.getNameAsString(); + + if (this.wrappedNode.getPackageDeclaration().isPresent() + && this.wrappedNode.getPackageDeclaration().get().getName().getIdentifier().equals(packageName(importString)) + && this.wrappedNode.getTypes().stream().anyMatch(it -> it.getName().getIdentifier().equals(toSimpleName(importString)))) { + // We are using a static import on a type defined in this file. It means the value was not found at + // a lower level so this will fail + return SymbolReference.unsolved(ResolvedMethodDeclaration.class); + } + + ResolvedTypeDeclaration ref = typeSolver.solveType(importString); + SymbolReference<ResolvedMethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver); + + if (method.isSolved()) { + return method; + } + } else{ + String qName = importDecl.getNameAsString(); + + if (qName.equals(name) || qName.endsWith("." + name)) { + String typeName = getType(qName); + ResolvedTypeDeclaration ref = typeSolver.solveType(typeName); + SymbolReference<ResolvedMethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver); + if (method.isSolved()) { + return method; + } + } + } + } + } + return SymbolReference.unsolved(ResolvedMethodDeclaration.class); + } + + /// + /// Private methods + /// + + private String getType(String qName) { + int index = qName.lastIndexOf('.'); + if (index == -1) { + throw new UnsupportedOperationException(); + } + String typeName = qName.substring(0, index); + return typeName; + } + + private String getMember(String qName) { + int index = qName.lastIndexOf('.'); + if (index == -1) { + throw new UnsupportedOperationException(); + } + String memberName = qName.substring(index + 1); + return memberName; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ConstructorContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ConstructorContext.java new file mode 100644 index 000000000..bebaa7313 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ConstructorContext.java @@ -0,0 +1,35 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.ConstructorDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +/** + * @author Federico Tomassetti + */ +public class ConstructorContext extends AbstractMethodLikeDeclarationContext<ConstructorDeclaration> { + + /// + /// Constructors + /// + + public ConstructorContext(ConstructorDeclaration wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ContextHelper.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ContextHelper.java new file mode 100644 index 000000000..e0eda24b0 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ContextHelper.java @@ -0,0 +1,74 @@ +/* + * 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.contexts; + +import com.github.javaparser.resolution.MethodUsage; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnonymousClassDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserInterfaceDeclaration; +import com.github.javaparser.symbolsolver.javassistmodel.JavassistClassDeclaration; +import com.github.javaparser.symbolsolver.javassistmodel.JavassistEnumDeclaration; +import com.github.javaparser.symbolsolver.javassistmodel.JavassistInterfaceDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionEnumDeclaration; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionInterfaceDeclaration; + +import java.util.List; +import java.util.Optional; + +/** + * @author Federico Tomassetti + */ +public class ContextHelper { + + private ContextHelper() { + // prevent instantiation + } + + public static Optional<MethodUsage> solveMethodAsUsage(ResolvedTypeDeclaration typeDeclaration, String name, + List<ResolvedType> argumentsTypes, TypeSolver typeSolver, + Context invokationContext, List<ResolvedType> typeParameters) { + if (typeDeclaration instanceof JavassistClassDeclaration) { + return ((JavassistClassDeclaration) typeDeclaration).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, typeParameters); + } else if (typeDeclaration instanceof JavassistInterfaceDeclaration) { + return ((JavassistInterfaceDeclaration) typeDeclaration).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, typeParameters); + } else if (typeDeclaration instanceof JavassistEnumDeclaration) { + return ((JavassistEnumDeclaration) typeDeclaration).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, typeParameters); + } else if (typeDeclaration instanceof ReflectionClassDeclaration) { + return ((ReflectionClassDeclaration) typeDeclaration).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, typeParameters); + } else if (typeDeclaration instanceof ReflectionInterfaceDeclaration) { + return ((ReflectionInterfaceDeclaration) typeDeclaration).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, typeParameters); + } else if (typeDeclaration instanceof ReflectionEnumDeclaration) { + return ((ReflectionEnumDeclaration) typeDeclaration).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, typeParameters); + } else if (typeDeclaration instanceof JavaParserClassDeclaration) { + return ((JavaParserClassDeclaration) typeDeclaration).getContext().solveMethodAsUsage(name, argumentsTypes, typeSolver); + } else if (typeDeclaration instanceof JavaParserInterfaceDeclaration) { + return ((JavaParserInterfaceDeclaration) typeDeclaration).getContext().solveMethodAsUsage(name, argumentsTypes, typeSolver); + } else if (typeDeclaration instanceof JavaParserEnumDeclaration) { + return ((JavaParserEnumDeclaration) typeDeclaration).getContext().solveMethodAsUsage(name, argumentsTypes, typeSolver); + } else if (typeDeclaration instanceof JavaParserAnonymousClassDeclaration) { + return ((JavaParserAnonymousClassDeclaration) typeDeclaration).getContext().solveMethodAsUsage(name, argumentsTypes, typeSolver); + } + throw new UnsupportedOperationException(typeDeclaration.toString()); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/EnumDeclarationContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/EnumDeclarationContext.java new file mode 100644 index 000000000..7f2365fe7 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/EnumDeclarationContext.java @@ -0,0 +1,82 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.EnumConstantDeclaration; +import com.github.javaparser.ast.body.EnumDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumConstantDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.List; + +/** + * @author Federico Tomassetti + */ +public class EnumDeclarationContext extends AbstractJavaParserContext<EnumDeclaration> { + + private JavaParserTypeDeclarationAdapter javaParserTypeDeclarationAdapter; + + public EnumDeclarationContext(EnumDeclaration wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + this.javaParserTypeDeclarationAdapter = new JavaParserTypeDeclarationAdapter(wrappedNode, typeSolver, + getDeclaration(), this); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + if (typeSolver == null) throw new IllegalArgumentException(); + + // among constants + for (EnumConstantDeclaration constant : wrappedNode.getEntries()) { + if (constant.getName().getId().equals(name)) { + return SymbolReference.solved(new JavaParserEnumConstantDeclaration(constant, typeSolver)); + } + } + + if (this.getDeclaration().hasField(name)) { + return SymbolReference.solved(this.getDeclaration().getField(name)); + } + + // then to parent + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + return javaParserTypeDeclarationAdapter.solveType(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return javaParserTypeDeclarationAdapter.solveMethod(name, argumentsTypes, staticOnly, typeSolver); + } + + /// + /// Private methods + /// + + private ResolvedReferenceTypeDeclaration getDeclaration() { + return new JavaParserEnumDeclaration(this.wrappedNode, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java new file mode 100644 index 000000000..65ccedf00 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java @@ -0,0 +1,104 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration; +import com.github.javaparser.resolution.types.ResolvedPrimitiveType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class FieldAccessContext extends AbstractJavaParserContext<FieldAccessExpr> { + + private static final String ARRAY_LENGTH_FIELD_NAME = "length"; + + public FieldAccessContext(FieldAccessExpr wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + if (wrappedNode.getName().toString().equals(name)) { + if (wrappedNode.getScope() instanceof ThisExpr) { + ResolvedType typeOfThis = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode); + return new SymbolSolver(typeSolver).solveSymbolInType(typeOfThis.asReferenceType().getTypeDeclaration(), name); + } + } + return JavaParserFactory.getContext(requireParentNode(wrappedNode), typeSolver).solveSymbol(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + return JavaParserFactory.getContext(requireParentNode(wrappedNode), typeSolver).solveType(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes, boolean staticOnly, TypeSolver typeSolver) { + return JavaParserFactory.getContext(requireParentNode(wrappedNode), typeSolver).solveMethod(name, parameterTypes, false, typeSolver); + } + + @Override + public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + Expression scope = wrappedNode.getScope(); + if (wrappedNode.getName().toString().equals(name)) { + ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(scope); + if (typeOfScope.isArray() && name.equals(ARRAY_LENGTH_FIELD_NAME)) { + return Optional.of(new Value(ResolvedPrimitiveType.INT, ARRAY_LENGTH_FIELD_NAME)); + } + if (typeOfScope.isReferenceType()) { + Optional<ResolvedType> typeUsage = typeOfScope.asReferenceType().getFieldType(name); + return typeUsage.map(resolvedType -> new Value(resolvedType, name)); + } else { + return Optional.empty(); + } + } else { + return getParent().solveSymbolAsValue(name, typeSolver); + } + } + + public SymbolReference<ResolvedFieldDeclaration> solveField(String name, TypeSolver typeSolver) { + Collection<ResolvedReferenceTypeDeclaration> rrtds = findTypeDeclarations(Optional.of(wrappedNode.getScope()), typeSolver); + for (ResolvedReferenceTypeDeclaration rrtd : rrtds) { + try { + return SymbolReference.solved(rrtd.getField(wrappedNode.getName().getId())); + } catch (Throwable t) { + } + } + return SymbolReference.unsolved(ResolvedFieldDeclaration.class); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ForStatementContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ForStatementContext.java new file mode 100644 index 000000000..cf3fe3b0c --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ForStatementContext.java @@ -0,0 +1,70 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.AssignExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; +import com.github.javaparser.ast.nodeTypes.NodeWithStatements; +import com.github.javaparser.ast.stmt.ForStmt; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.List; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +public class ForStatementContext extends AbstractJavaParserContext<ForStmt> { + + public ForStatementContext(ForStmt wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + for (Expression expression : wrappedNode.getInitialization()) { + if (expression instanceof VariableDeclarationExpr) { + VariableDeclarationExpr variableDeclarationExpr = (VariableDeclarationExpr) expression; + for (VariableDeclarator variableDeclarator : variableDeclarationExpr.getVariables()) { + if (variableDeclarator.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserSymbolDeclaration.localVar(variableDeclarator, typeSolver)); + } + } + } else if (!(expression instanceof AssignExpr || expression instanceof MethodCallExpr)) { + throw new UnsupportedOperationException(expression.getClass().getCanonicalName()); + } + } + + if (requireParentNode(wrappedNode) instanceof NodeWithStatements) { + return StatementContext.solveInBlock(name, typeSolver, wrappedNode); + } else { + return getParent().solveSymbol(name, typeSolver); + } + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, + boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ForechStatementContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ForechStatementContext.java new file mode 100644 index 000000000..ba412023d --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/ForechStatementContext.java @@ -0,0 +1,61 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ForeachStmt; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.List; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +public class ForechStatementContext extends AbstractJavaParserContext<ForeachStmt> { + + public ForechStatementContext(ForeachStmt wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + if (wrappedNode.getVariable().getVariables().size() != 1) { + throw new IllegalStateException(); + } + VariableDeclarator variableDeclarator = wrappedNode.getVariable().getVariables().get(0); + if (variableDeclarator.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserSymbolDeclaration.localVar(variableDeclarator, typeSolver)); + } else { + if (requireParentNode(wrappedNode) instanceof BlockStmt) { + return StatementContext.solveInBlock(name, typeSolver, wrappedNode); + } else { + return getParent().solveSymbol(name, typeSolver); + } + } + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, + boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java new file mode 100644 index 000000000..993f42d29 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java @@ -0,0 +1,133 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.contexts; + +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters; +import com.github.javaparser.ast.type.TypeParameter; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.reflectionmodel.*; +import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic; +import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserTypeDeclarationAdapter { + + private com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode; + private TypeSolver typeSolver; + private Context context; + private ResolvedReferenceTypeDeclaration typeDeclaration; + + public JavaParserTypeDeclarationAdapter(com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode, TypeSolver typeSolver, + ResolvedReferenceTypeDeclaration typeDeclaration, + Context context) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + this.typeDeclaration = typeDeclaration; + this.context = context; + } + + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (this.wrappedNode.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(wrappedNode)); + } + + // Internal classes + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + com.github.javaparser.ast.body.TypeDeclaration<?> internalType = (com.github.javaparser.ast.body.TypeDeclaration<?>) member; + if (internalType.getName().getId().equals(name)) { + return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(internalType)); + } else if (name.startsWith(String.format("%s.%s", wrappedNode.getName(), internalType.getName()))) { + return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(wrappedNode.getName().getId().length() + 1), typeSolver); + } else if (name.startsWith(String.format("%s.", internalType.getName()))) { + return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(internalType.getName().getId().length() + 1), typeSolver); + } + } + } + + if (wrappedNode instanceof NodeWithTypeParameters) { + NodeWithTypeParameters<?> nodeWithTypeParameters = (NodeWithTypeParameters<?>) wrappedNode; + for (TypeParameter astTpRaw : nodeWithTypeParameters.getTypeParameters()) { + TypeParameter astTp = astTpRaw; + if (astTp.getName().getId().equals(name)) { + return SymbolReference.solved(new JavaParserTypeParameter(astTp, typeSolver)); + } + } + } + + // Look into extended classes and implemented interfaces + for (ResolvedReferenceType ancestor : this.typeDeclaration.getAncestors()) { + try { + for (ResolvedTypeDeclaration internalTypeDeclaration : ancestor.getTypeDeclaration().internalTypes()) { + if (internalTypeDeclaration.getName().equals(name)) { + return SymbolReference.solved(internalTypeDeclaration); + } + } + } catch (UnsupportedOperationException e) { + // just continue using the next ancestor + } + } + + return context.getParent().solveType(name, typeSolver); + } + + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + List<ResolvedMethodDeclaration> candidateMethods = typeDeclaration.getDeclaredMethods().stream() + .filter(m -> m.getName().equals(name)) + .filter(m -> !staticOnly || (staticOnly && m.isStatic())) + .collect(Collectors.toList()); + // We want to avoid infinite recursion in case of Object having Object as ancestor + if (!Object.class.getCanonicalName().equals(typeDeclaration.getQualifiedName())) { + for (ResolvedReferenceType ancestor : typeDeclaration.getAncestors()) { + // Avoid recursion on self + if (typeDeclaration != ancestor.getTypeDeclaration()) { + SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic + .solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver); + // consider methods from superclasses and only default methods from interfaces : + // not true, we should keep abstract as a valid candidate + // abstract are removed in MethodResolutionLogic.isApplicable is necessary + if (res.isSolved()) { + candidateMethods.add(res.getCorrespondingDeclaration()); + } + } + } + } + // We want to avoid infinite recursion when a class is using its own method + // see issue #75 + if (candidateMethods.isEmpty()) { + SymbolReference<ResolvedMethodDeclaration> parentSolution = context.getParent().solveMethod(name, argumentsTypes, staticOnly, typeSolver); + if (parentSolution.isSolved()) { + candidateMethods.add(parentSolution.getCorrespondingDeclaration()); + } + } + + // if is interface and candidate method list is empty, we should check the Object Methods + if (candidateMethods.isEmpty() && typeDeclaration.isInterface()) { + SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver); + if (res.isSolved()) { + candidateMethods.add(res.getCorrespondingDeclaration()); + } + } + + return MethodResolutionLogic.findMostApplicable(candidateMethods, name, argumentsTypes, typeSolver); + } + + public SymbolReference<ResolvedConstructorDeclaration> solveConstructor(List<ResolvedType> argumentsTypes, TypeSolver typeSolver) { + if (typeDeclaration instanceof ResolvedClassDeclaration) { + return ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) typeDeclaration).getConstructors(), argumentsTypes, typeSolver); + } + return SymbolReference.unsolved(ResolvedConstructorDeclaration.class); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/LambdaExprContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/LambdaExprContext.java new file mode 100644 index 000000000..3c34facfe --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/LambdaExprContext.java @@ -0,0 +1,193 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.resolution.MethodUsage; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedLambdaConstraintType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.logic.FunctionalInterfaceLogic; +import com.github.javaparser.symbolsolver.logic.InferenceContext; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.reflectionmodel.MyObjectProvider; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import java.util.*; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class LambdaExprContext extends AbstractJavaParserContext<LambdaExpr> { + + public LambdaExprContext(LambdaExpr wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + for (Parameter parameter : wrappedNode.getParameters()) { + SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(parameter, typeSolver); + int index = 0; + for (ResolvedValueDeclaration decl : sb.getSymbolDeclarations()) { + if (decl.getName().equals(name)) { + if (requireParentNode(wrappedNode) instanceof MethodCallExpr) { + MethodCallExpr methodCallExpr = (MethodCallExpr) requireParentNode(wrappedNode); + MethodUsage methodUsage = JavaParserFacade.get(typeSolver).solveMethodAsUsage(methodCallExpr); + int i = pos(methodCallExpr, wrappedNode); + ResolvedType lambdaType = methodUsage.getParamTypes().get(i); + + // Get the functional method in order for us to resolve it's type arguments properly + Optional<MethodUsage> functionalMethodOpt = FunctionalInterfaceLogic.getFunctionalMethod(lambdaType); + if (functionalMethodOpt.isPresent()){ + MethodUsage functionalMethod = functionalMethodOpt.get(); + InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE); + + // Resolve each type variable of the lambda, and use this later to infer the type of each + // implicit parameter + inferenceContext.addPair(lambdaType, new ReferenceTypeImpl(lambdaType.asReferenceType().getTypeDeclaration(), typeSolver)); + + // Find the position of this lambda argument + boolean found = false; + int lambdaParamIndex; + for (lambdaParamIndex = 0; lambdaParamIndex < wrappedNode.getParameters().size(); lambdaParamIndex++){ + if (wrappedNode.getParameter(lambdaParamIndex).getName().getIdentifier().equals(name)){ + found = true; + break; + } + } + if (!found) { return Optional.empty(); } + + // Now resolve the argument type using the inference context + ResolvedType argType = inferenceContext.resolve(inferenceContext.addSingle(functionalMethod.getParamType(lambdaParamIndex))); + + ResolvedLambdaConstraintType conType; + if (argType.isWildcard()){ + conType = ResolvedLambdaConstraintType.bound(argType.asWildcard().getBoundedType()); + } else { + conType = ResolvedLambdaConstraintType.bound(argType); + } + Value value = new Value(conType, name); + return Optional.of(value); + } else{ + return Optional.empty(); + } + } else if (requireParentNode(wrappedNode) instanceof VariableDeclarator) { + VariableDeclarator variableDeclarator = (VariableDeclarator) requireParentNode(wrappedNode); + ResolvedType t = JavaParserFacade.get(typeSolver).convertToUsageVariableType(variableDeclarator); + Optional<MethodUsage> functionalMethod = FunctionalInterfaceLogic.getFunctionalMethod(t); + if (functionalMethod.isPresent()) { + ResolvedType lambdaType = functionalMethod.get().getParamType(index); + + // Replace parameter from declarator + Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes = new HashMap<>(); + if (lambdaType.isReferenceType()) { + for (com.github.javaparser.utils.Pair<ResolvedTypeParameterDeclaration, ResolvedType> entry : lambdaType.asReferenceType().getTypeParametersMap()) { + if (entry.b.isTypeVariable() && entry.b.asTypeParameter().declaredOnType()) { + ResolvedType ot = t.asReferenceType().typeParametersMap().getValue(entry.a); + lambdaType = lambdaType.replaceTypeVariables(entry.a, ot, inferredTypes); + } + } + } else if (lambdaType.isTypeVariable() && lambdaType.asTypeParameter().declaredOnType()) { + lambdaType = t.asReferenceType().typeParametersMap().getValue(lambdaType.asTypeParameter()); + } + + Value value = new Value(lambdaType, name); + return Optional.of(value); + } else { + throw new UnsupportedOperationException(); + } + } else { + throw new UnsupportedOperationException(); + } + } + index++; + } + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbolAsValue(name, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + for (Parameter parameter : wrappedNode.getParameters()) { + SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(parameter, typeSolver); + SymbolReference<ResolvedValueDeclaration> symbolReference = solveWith(sb, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + return getParent().solveType(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod( + String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } + + /// + /// Protected methods + /// + + protected final Optional<Value> solveWithAsValue(SymbolDeclarator symbolDeclarator, String name, TypeSolver typeSolver) { + for (ResolvedValueDeclaration decl : symbolDeclarator.getSymbolDeclarations()) { + if (decl.getName().equals(name)) { + + throw new UnsupportedOperationException(); + } + } + return Optional.empty(); + } + + /// + /// Private methods + /// + + private int pos(MethodCallExpr callExpr, Expression param) { + int i = 0; + for (Expression p : callExpr.getArguments()) { + if (p == param) { + return i; + } + i++; + } + throw new IllegalArgumentException(); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodCallExprContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodCallExprContext.java new file mode 100644 index 000000000..ca9f07c42 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodCallExprContext.java @@ -0,0 +1,433 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +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.JavaParserFacade; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.model.typesystem.*; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; +import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; +import com.github.javaparser.utils.Pair; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class MethodCallExprContext extends AbstractJavaParserContext<MethodCallExpr> { + + /// + /// Constructors + /// + + public MethodCallExprContext(MethodCallExpr wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + /// + /// Public methods + /// + + @Override + public Optional<ResolvedType> solveGenericType(String name, TypeSolver typeSolver) { + if(wrappedNode.getScope().isPresent()){ + ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(wrappedNode.getScope().get()); + Optional<ResolvedType> res = typeOfScope.asReferenceType().getGenericParameterByName(name); + return res; + } else{ + return Optional.empty(); + } + } + + @Override + public String toString() { + return "MethodCallExprContext{wrapped=" + wrappedNode + "}"; + } + + @Override + public Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver) { + if (wrappedNode.getScope().isPresent()) { + Expression scope = wrappedNode.getScope().get(); + // Consider static method calls + if (scope instanceof NameExpr) { + String className = ((NameExpr) scope).getName().getId(); + SymbolReference<ResolvedTypeDeclaration> ref = solveType(className, typeSolver); + if (ref.isSolved()) { + SymbolReference<ResolvedMethodDeclaration> m = MethodResolutionLogic.solveMethodInType(ref.getCorrespondingDeclaration(), name, argumentsTypes, typeSolver); + if (m.isSolved()) { + MethodUsage methodUsage = new MethodUsage(m.getCorrespondingDeclaration()); + methodUsage = resolveMethodTypeParametersFromExplicitList(typeSolver, methodUsage); + methodUsage = resolveMethodTypeParameters(methodUsage, argumentsTypes); + return Optional.of(methodUsage); + } else { + throw new UnsolvedSymbolException(ref.getCorrespondingDeclaration().toString(), + "Method '" + name + "' with parameterTypes " + argumentsTypes); + } + } + } + + ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(scope); + // we can replace the parameter types from the scope into the typeParametersValues + + Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes = new HashMap<>(); + for (int i = 0; i < argumentsTypes.size(); i++) { + // by replacing types I can also find new equivalences + // for example if I replace T=U with String because I know that T=String I can derive that also U equal String + ResolvedType originalArgumentType = argumentsTypes.get(i); + ResolvedType updatedArgumentType = usingParameterTypesFromScope(typeOfScope, originalArgumentType, inferredTypes); + argumentsTypes.set(i, updatedArgumentType); + } + for (int i = 0; i < argumentsTypes.size(); i++) { + ResolvedType updatedArgumentType = applyInferredTypes(argumentsTypes.get(i), inferredTypes); + argumentsTypes.set(i, updatedArgumentType); + } + + return solveMethodAsUsage(typeOfScope, name, argumentsTypes, typeSolver, this); + } else { + Context parentContext = getParent(); + while (parentContext instanceof MethodCallExprContext) { + parentContext = parentContext.getParent(); + } + return parentContext.solveMethodAsUsage(name, argumentsTypes, typeSolver); + } + } + + private MethodUsage resolveMethodTypeParametersFromExplicitList(TypeSolver typeSolver, MethodUsage methodUsage) { + if (wrappedNode.getTypeArguments().isPresent()) { + final List<ResolvedType> typeArguments = new ArrayList<>(); + for (com.github.javaparser.ast.type.Type ty : wrappedNode.getTypeArguments().get()) { + typeArguments.add(JavaParserFacade.get(typeSolver).convertToUsage(ty)); + } + + List<ResolvedTypeParameterDeclaration> tyParamDecls = methodUsage.getDeclaration().getTypeParameters(); + if (tyParamDecls.size() == typeArguments.size()) { + for (int i = 0; i < tyParamDecls.size(); i++) { + methodUsage = methodUsage.replaceTypeParameter(tyParamDecls.get(i), typeArguments.get(i)); + } + } + } + + return methodUsage; + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + Context parentContext = getParent(); + return parentContext.solveSymbolAsValue(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + Collection<ResolvedReferenceTypeDeclaration> rrtds = findTypeDeclarations(wrappedNode.getScope(), typeSolver); + for (ResolvedReferenceTypeDeclaration rrtd : rrtds) { + SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic.solveMethodInType(rrtd, name, argumentsTypes, false, typeSolver); + if (res.isSolved()) { + return res; + } + } + return SymbolReference.unsolved(ResolvedMethodDeclaration.class); + } + + /// + /// Private methods + /// + + private Optional<MethodUsage> solveMethodAsUsage(ResolvedReferenceType refType, String name, + List<ResolvedType> argumentsTypes, TypeSolver typeSolver, + Context invokationContext) { + Optional<MethodUsage> ref = ContextHelper.solveMethodAsUsage(refType.getTypeDeclaration(), name, argumentsTypes, typeSolver, invokationContext, refType.typeParametersValues()); + if (ref.isPresent()) { + MethodUsage methodUsage = ref.get(); + + methodUsage = resolveMethodTypeParametersFromExplicitList(typeSolver, methodUsage); + + // At this stage I should derive from the context and the value some information on the type parameters + // for example, when calling: + // myStream.collect(Collectors.toList()) + // I should be able to figure out that considering the type of the stream (e.g., Stream<String>) + // and considering that Stream has this method: + // + // <R,A> R collect(Collector<? super T,A,R> collector) + // + // and collector has this method: + // + // static <T> Collector<T,?,List<T>> toList() + // + // In this case collect.R has to be equal to List<toList.T> + // And toList.T has to be equal to ? super Stream.T + // Therefore R has to be equal to List<? super Stream.T>. + // In our example Stream.T equal to String, so the R (and the result of the call to collect) is + // List<? super String> + + Map<ResolvedTypeParameterDeclaration, ResolvedType> derivedValues = new HashMap<>(); + for (int i = 0; i < methodUsage.getParamTypes().size(); i++) { + ResolvedParameterDeclaration parameter = methodUsage.getDeclaration().getParam(i); + ResolvedType parameterType = parameter.getType(); + if (parameter.isVariadic()) { + parameterType = parameterType.asArrayType().getComponentType(); + } + inferTypes(argumentsTypes.get(i), parameterType, derivedValues); + } + + for (Map.Entry<ResolvedTypeParameterDeclaration, ResolvedType> entry : derivedValues.entrySet()){ + methodUsage = methodUsage.replaceTypeParameter(entry.getKey(), entry.getValue()); + } + + ResolvedType returnType = refType.useThisTypeParametersOnTheGivenType(methodUsage.returnType()); + if (returnType != methodUsage.returnType()) { + methodUsage = methodUsage.replaceReturnType(returnType); + } + for (int i = 0; i < methodUsage.getParamTypes().size(); i++) { + ResolvedType replaced = refType.useThisTypeParametersOnTheGivenType(methodUsage.getParamTypes().get(i)); + methodUsage = methodUsage.replaceParamType(i, replaced); + } + return Optional.of(methodUsage); + } else { + return ref; + } + } + + private void inferTypes(ResolvedType source, ResolvedType target, Map<ResolvedTypeParameterDeclaration, ResolvedType> mappings) { + if (source.equals(target)) { + return; + } + if (source.isReferenceType() && target.isReferenceType()) { + ResolvedReferenceType sourceRefType = source.asReferenceType(); + ResolvedReferenceType targetRefType = target.asReferenceType(); + if (sourceRefType.getQualifiedName().equals(targetRefType.getQualifiedName())) { + if (!sourceRefType.isRawType() && !targetRefType.isRawType()) { + for (int i = 0; i < sourceRefType.typeParametersValues().size(); i++) { + inferTypes(sourceRefType.typeParametersValues().get(i), targetRefType.typeParametersValues().get(i), mappings); + } + } + } + return; + } + if (source.isReferenceType() && target.isWildcard()) { + if (target.asWildcard().isBounded()) { + inferTypes(source, target.asWildcard().getBoundedType(), mappings); + return; + } + return; + } + if (source.isWildcard() && target.isWildcard()) { + if (source.asWildcard().isBounded() && target.asWildcard().isBounded()){ + inferTypes(source.asWildcard().getBoundedType(), target.asWildcard().getBoundedType(), mappings); + } + return; + } + if (source.isReferenceType() && target.isTypeVariable()) { + mappings.put(target.asTypeParameter(), source); + return; + } + if (source.isWildcard() && target.isTypeVariable()) { + mappings.put(target.asTypeParameter(), source); + return; + } + if (source.isArray() && target.isWildcard()){ + if(target.asWildcard().isBounded()){ + inferTypes(source, target.asWildcard().getBoundedType(), mappings); + return; + } + return; + } + if (source.isArray() && target.isTypeVariable()) { + mappings.put(target.asTypeParameter(), source); + return; + } + + if (source.isWildcard() && target.isReferenceType()){ + if (source.asWildcard().isBounded()){ + inferTypes(source.asWildcard().getBoundedType(), target, mappings); + } + return; + } + if (source.isConstraint() && target.isReferenceType()){ + inferTypes(source.asConstraintType().getBound(), target, mappings); + return; + } + + if (source.isConstraint() && target.isTypeVariable()){ + inferTypes(source.asConstraintType().getBound(), target, mappings); + return; + } + if (source.isTypeVariable() && target.isTypeVariable()) { + mappings.put(target.asTypeParameter(), source); + return; + } + if (source.isPrimitive() || target.isPrimitive()) { + return; + } + if (source.isNull()) { + return; + } + throw new RuntimeException(source.describe() + " " + target.describe()); + } + + private MethodUsage resolveMethodTypeParameters(MethodUsage methodUsage, List<ResolvedType> actualParamTypes) { + Map<ResolvedTypeParameterDeclaration, ResolvedType> matchedTypeParameters = new HashMap<>(); + + if (methodUsage.getDeclaration().hasVariadicParameter()) { + if (actualParamTypes.size() == methodUsage.getDeclaration().getNumberOfParams()) { + // the varargs parameter is an Array, so extract the inner type + ResolvedType expectedType = + methodUsage.getDeclaration().getLastParam().getType().asArrayType().getComponentType(); + // the varargs corresponding type can be either T or Array<T> + ResolvedType actualType = + actualParamTypes.get(actualParamTypes.size() - 1).isArray() ? + actualParamTypes.get(actualParamTypes.size() - 1).asArrayType().getComponentType() : + actualParamTypes.get(actualParamTypes.size() - 1); + if (!expectedType.isAssignableBy(actualType)) { + for (ResolvedTypeParameterDeclaration tp : methodUsage.getDeclaration().getTypeParameters()) { + expectedType = MethodResolutionLogic.replaceTypeParam(expectedType, tp, typeSolver); + } + } + if (!expectedType.isAssignableBy(actualType)) { + // ok, then it needs to be wrapped + throw new UnsupportedOperationException( + String.format("Unable to resolve the type typeParametersValues in a MethodUsage. Expected type: %s, Actual type: %s. Method Declaration: %s. MethodUsage: %s", + expectedType, + actualType, + methodUsage.getDeclaration(), + methodUsage)); + } + // match only the varargs type + matchTypeParameters(expectedType, actualType, matchedTypeParameters); + } else { + return methodUsage; + } + } + + int until = methodUsage.getDeclaration().hasVariadicParameter() ? + actualParamTypes.size() - 1 : + actualParamTypes.size(); + + for (int i = 0; i < until; i++) { + ResolvedType expectedType = methodUsage.getParamType(i); + ResolvedType actualType = actualParamTypes.get(i); + matchTypeParameters(expectedType, actualType, matchedTypeParameters); + } + for (ResolvedTypeParameterDeclaration tp : matchedTypeParameters.keySet()) { + methodUsage = methodUsage.replaceTypeParameter(tp, matchedTypeParameters.get(tp)); + } + return methodUsage; + } + + private void matchTypeParameters(ResolvedType expectedType, ResolvedType actualType, Map<ResolvedTypeParameterDeclaration, ResolvedType> matchedTypeParameters) { + if (expectedType.isTypeVariable()) { + if (!actualType.isTypeVariable() && !actualType.isReferenceType()) { + throw new UnsupportedOperationException(actualType.getClass().getCanonicalName()); + } + matchedTypeParameters.put(expectedType.asTypeParameter(), actualType); + } else if (expectedType.isArray()) { + if (!actualType.isArray()) { + throw new UnsupportedOperationException(actualType.getClass().getCanonicalName()); + } + matchTypeParameters( + expectedType.asArrayType().getComponentType(), + actualType.asArrayType().getComponentType(), + matchedTypeParameters); + } else if (expectedType.isReferenceType()) { + // avoid cases where the actual type has no type parameters but the expected one has. Such as: "classX extends classY<Integer>" + if (actualType.isReferenceType() && actualType.asReferenceType().typeParametersValues().size() > 0) { + int i = 0; + for (ResolvedType tp : expectedType.asReferenceType().typeParametersValues()) { + matchTypeParameters(tp, actualType.asReferenceType().typeParametersValues().get(i), matchedTypeParameters); + i++; + } + } + } else if (expectedType.isPrimitive()) { + // nothing to do + } else if (expectedType.isWildcard()) { + // nothing to do + } else { + throw new UnsupportedOperationException(expectedType.getClass().getCanonicalName()); + } + } + + private Optional<MethodUsage> solveMethodAsUsage(ResolvedTypeVariable tp, String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver, Context invokationContext) { + for (ResolvedTypeParameterDeclaration.Bound bound : tp.asTypeParameter().getBounds()) { + Optional<MethodUsage> methodUsage = solveMethodAsUsage(bound.getType(), name, argumentsTypes, typeSolver, invokationContext); + if (methodUsage.isPresent()) { + return methodUsage; + } + } + return Optional.empty(); + } + + private Optional<MethodUsage> solveMethodAsUsage(ResolvedType type, String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver, Context invokationContext) { + if (type instanceof ResolvedReferenceType) { + return solveMethodAsUsage((ResolvedReferenceType) type, name, argumentsTypes, typeSolver, invokationContext); + } else if (type instanceof ResolvedTypeVariable) { + return solveMethodAsUsage((ResolvedTypeVariable) type, name, argumentsTypes, typeSolver, invokationContext); + } else if (type instanceof ResolvedWildcard) { + ResolvedWildcard wildcardUsage = (ResolvedWildcard) type; + if (wildcardUsage.isSuper()) { + return solveMethodAsUsage(wildcardUsage.getBoundedType(), name, argumentsTypes, typeSolver, invokationContext); + } else if (wildcardUsage.isExtends()) { + throw new UnsupportedOperationException("extends wildcard"); + } else { + throw new UnsupportedOperationException("unbounded wildcard"); + } + } else if (type instanceof ResolvedLambdaConstraintType){ + ResolvedLambdaConstraintType constraintType = (ResolvedLambdaConstraintType) type; + return solveMethodAsUsage(constraintType.getBound(), name, argumentsTypes, typeSolver, invokationContext); + } else if (type instanceof ResolvedArrayType) { + // An array inherits methods from Object not from it's component type + return solveMethodAsUsage(new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver), name, argumentsTypes, typeSolver, invokationContext); + } else { + throw new UnsupportedOperationException("type usage: " + type.getClass().getCanonicalName()); + } + } + + private ResolvedType usingParameterTypesFromScope(ResolvedType scope, ResolvedType type, Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes) { + if (type.isReferenceType()) { + for (Pair<ResolvedTypeParameterDeclaration, ResolvedType> entry : type.asReferenceType().getTypeParametersMap()) { + if (entry.a.declaredOnType() && scope.asReferenceType().getGenericParameterByName(entry.a.getName()).isPresent()) { + type = type.replaceTypeVariables(entry.a, scope.asReferenceType().getGenericParameterByName(entry.a.getName()).get(), inferredTypes); + } + } + return type; + } else { + return type; + } + } + + private ResolvedType applyInferredTypes(ResolvedType type, Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes) { + for (ResolvedTypeParameterDeclaration tp : inferredTypes.keySet()) { + type = type.replaceTypeVariables(tp, inferredTypes.get(tp), inferredTypes); + } + return type; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodContext.java new file mode 100644 index 000000000..9a7530b18 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodContext.java @@ -0,0 +1,35 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +/** + * @author Federico Tomassetti + */ +public class MethodContext extends AbstractMethodLikeDeclarationContext<MethodDeclaration> { + + /// + /// Constructors + /// + + public MethodContext(MethodDeclaration wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/StatementContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/StatementContext.java new file mode 100644 index 000000000..8acab7a8a --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/StatementContext.java @@ -0,0 +1,200 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.nodeTypes.NodeWithStatements; +import com.github.javaparser.ast.stmt.IfStmt; +import com.github.javaparser.ast.stmt.Statement; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import java.util.List; +import java.util.Optional; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class StatementContext<N extends Statement> extends AbstractJavaParserContext<N> { + + public StatementContext(N wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + public static SymbolReference<? extends ResolvedValueDeclaration> solveInBlock(String name, TypeSolver typeSolver, Statement stmt) { + if (!(requireParentNode(stmt) instanceof NodeWithStatements)) { + throw new IllegalArgumentException(); + } + NodeWithStatements<?> blockStmt = (NodeWithStatements<?>) requireParentNode(stmt); + int position = -1; + for (int i = 0; i < blockStmt.getStatements().size(); i++) { + if (blockStmt.getStatements().get(i).equals(stmt)) { + position = i; + } + } + if (position == -1) { + throw new RuntimeException(); + } + for (int i = position - 1; i >= 0; i--) { + SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(blockStmt.getStatements().get(i), typeSolver); + SymbolReference<? extends ResolvedValueDeclaration> symbolReference = solveWith(symbolDeclarator, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + } + + // if nothing is found we should ask the parent context + return JavaParserFactory.getContext(requireParentNode(stmt), typeSolver).solveSymbol(name, typeSolver); + } + + public static Optional<Value> solveInBlockAsValue(String name, TypeSolver typeSolver, Statement stmt) { + if (!(requireParentNode(stmt) instanceof NodeWithStatements)) { + throw new IllegalArgumentException(); + } + NodeWithStatements<?> blockStmt = (NodeWithStatements<?>) requireParentNode(stmt); + int position = -1; + for (int i = 0; i < blockStmt.getStatements().size(); i++) { + if (blockStmt.getStatements().get(i).equals(stmt)) { + position = i; + } + } + if (position == -1) { + throw new RuntimeException(); + } + for (int i = position - 1; i >= 0; i--) { + SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(blockStmt.getStatements().get(i), typeSolver); + SymbolReference<? extends ResolvedValueDeclaration> symbolReference = solveWith(symbolDeclarator, name); + if (symbolReference.isSolved()) { + return Optional.of(Value.from(symbolReference.getCorrespondingDeclaration())); + } + } + + // if nothing is found we should ask the parent context + return JavaParserFactory.getContext(requireParentNode(stmt), typeSolver).solveSymbolAsValue(name, typeSolver); + } + + @Override + public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + + // if we're in a multiple Variable declaration line (for ex: double a=0, b=a;) + SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(wrappedNode, typeSolver); + Optional<Value> symbolReference = solveWithAsValue(symbolDeclarator, name, typeSolver); + if (symbolReference.isPresent()) { + return symbolReference; + } + + // we should look in all the statements preceding, treating them as SymbolDeclarators + if (requireParentNode(wrappedNode) instanceof com.github.javaparser.ast.body.MethodDeclaration) { + return getParent().solveSymbolAsValue(name, typeSolver); + } + if (requireParentNode(wrappedNode) instanceof LambdaExpr) { + return getParent().solveSymbolAsValue(name, typeSolver); + } + if (requireParentNode(wrappedNode) instanceof IfStmt) { + return getParent().solveSymbolAsValue(name, typeSolver); + } + if (!(requireParentNode(wrappedNode) instanceof NodeWithStatements)) { + return getParent().solveSymbolAsValue(name, typeSolver); + } + NodeWithStatements<?> nodeWithStmt = (NodeWithStatements<?>) requireParentNode(wrappedNode); + int position = -1; + for (int i = 0; i < nodeWithStmt.getStatements().size(); i++) { + if (nodeWithStmt.getStatements().get(i).equals(wrappedNode)) { + position = i; + } + } + if (position == -1) { + throw new RuntimeException(); + } + for (int i = position - 1; i >= 0; i--) { + symbolDeclarator = JavaParserFactory.getSymbolDeclarator(nodeWithStmt.getStatements().get(i), typeSolver); + symbolReference = solveWithAsValue(symbolDeclarator, name, typeSolver); + if (symbolReference.isPresent()) { + return symbolReference; + } + } + + // if nothing is found we should ask the parent context + Context parentContext = getParent(); + return parentContext.solveSymbolAsValue(name, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + + // if we're in a multiple Variable declaration line (for ex: double a=0, b=a;) + SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(wrappedNode, typeSolver); + SymbolReference<? extends ResolvedValueDeclaration> symbolReference = solveWith(symbolDeclarator, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + + // we should look in all the statements preceding, treating them as SymbolDeclarators + if (requireParentNode(wrappedNode) instanceof com.github.javaparser.ast.body.MethodDeclaration) { + return getParent().solveSymbol(name, typeSolver); + } + if (requireParentNode(wrappedNode) instanceof com.github.javaparser.ast.body.ConstructorDeclaration) { + return getParent().solveSymbol(name, typeSolver); + } + if (requireParentNode(wrappedNode) instanceof LambdaExpr) { + return getParent().solveSymbol(name, typeSolver); + } + if (!(requireParentNode(wrappedNode) instanceof NodeWithStatements)) { + return getParent().solveSymbol(name, typeSolver); + } + NodeWithStatements<?> nodeWithStmt = (NodeWithStatements<?>) requireParentNode(wrappedNode); + int position = -1; + for (int i = 0; i < nodeWithStmt.getStatements().size(); i++) { + if (nodeWithStmt.getStatements().get(i).equals(wrappedNode)) { + position = i; + } + } + if (position == -1) { + throw new RuntimeException(); + } + for (int i = position - 1; i >= 0; i--) { + symbolDeclarator = JavaParserFactory.getSymbolDeclarator(nodeWithStmt.getStatements().get(i), typeSolver); + symbolReference = solveWith(symbolDeclarator, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + } + + // if nothing is found we should ask the parent context + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } + + @Override + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + return getParent().solveType(name, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java new file mode 100644 index 000000000..15967295b --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java @@ -0,0 +1,80 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.stmt.Statement; +import com.github.javaparser.ast.stmt.SwitchEntryStmt; +import com.github.javaparser.ast.stmt.SwitchStmt; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +import java.util.List; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class SwitchEntryContext extends AbstractJavaParserContext<SwitchEntryStmt> { + + public SwitchEntryContext(SwitchEntryStmt wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + SwitchStmt switchStmt = (SwitchStmt) requireParentNode(wrappedNode); + ResolvedType type = JavaParserFacade.get(typeSolver).getType(switchStmt.getSelector()); + if (type.isReferenceType() && type.asReferenceType().getTypeDeclaration().isEnum()) { + if (type instanceof ReferenceTypeImpl) { + ReferenceTypeImpl typeUsageOfTypeDeclaration = (ReferenceTypeImpl) type; + if (typeUsageOfTypeDeclaration.getTypeDeclaration().hasField(name)) { + return SymbolReference.solved(typeUsageOfTypeDeclaration.getTypeDeclaration().getField(name)); + } + } else { + throw new UnsupportedOperationException(); + } + } + + // look for declaration in other switch statements + for (SwitchEntryStmt seStmt : switchStmt.getEntries()) { + if (!seStmt.equals(wrappedNode)) { + for (Statement stmt : seStmt.getStatements()) { + SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(stmt, typeSolver); + SymbolReference<? extends ResolvedValueDeclaration> symbolReference = solveWith(symbolDeclarator, name); + if (symbolReference.isSolved()) { + return symbolReference; + } + } + } + } + + return getParent().solveSymbol(name, typeSolver); + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/TryWithResourceContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/TryWithResourceContext.java new file mode 100644 index 000000000..80932e563 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/TryWithResourceContext.java @@ -0,0 +1,88 @@ +/* + * 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.contexts; + +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.TryStmt; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; + +import java.util.List; +import java.util.Optional; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +public class TryWithResourceContext extends AbstractJavaParserContext<TryStmt> { + + public TryWithResourceContext(TryStmt wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { + for (Expression expr : wrappedNode.getResources()) { + if (expr instanceof VariableDeclarationExpr) { + for (VariableDeclarator v : ((VariableDeclarationExpr)expr).getVariables()) { + if (v.getName().getIdentifier().equals(name)) { + JavaParserSymbolDeclaration decl = JavaParserSymbolDeclaration.localVar(v, typeSolver); + return Optional.of(Value.from(decl)); + } + } + } + } + + if (requireParentNode(wrappedNode) instanceof BlockStmt) { + return StatementContext.solveInBlockAsValue(name, typeSolver, wrappedNode); + } else { + return getParent().solveSymbolAsValue(name, typeSolver); + } + } + + @Override + public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { + for (Expression expr : wrappedNode.getResources()) { + if (expr instanceof VariableDeclarationExpr) { + for (VariableDeclarator v : ((VariableDeclarationExpr)expr).getVariables()) { + if (v.getName().getIdentifier().equals(name)) { + return SymbolReference.solved(JavaParserSymbolDeclaration.localVar(v, typeSolver)); + } + } + } + } + + if (requireParentNode(wrappedNode) instanceof BlockStmt) { + return StatementContext.solveInBlock(name, typeSolver, wrappedNode); + } else { + return getParent().solveSymbol(name, typeSolver); + } + } + + @Override + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, + boolean staticOnly, TypeSolver typeSolver) { + return getParent().solveMethod(name, argumentsTypes, false, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/DefaultConstructorDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/DefaultConstructorDeclaration.java new file mode 100644 index 000000000..aff7c7c85 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/DefaultConstructorDeclaration.java @@ -0,0 +1,82 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.resolution.declarations.ResolvedClassDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedParameterDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; + +import java.util.Collections; +import java.util.List; + +/** + * This represents the default constructor added by the compiler for objects not declaring one. + * It takes no parameters. See JLS 8.8.9 for details. + * + * @author Federico Tomassetti + */ +class DefaultConstructorDeclaration implements ResolvedConstructorDeclaration { + + private ResolvedClassDeclaration classDeclaration; + + DefaultConstructorDeclaration(ResolvedClassDeclaration classDeclaration) { + this.classDeclaration = classDeclaration; + } + + @Override + public ResolvedClassDeclaration declaringType() { + return classDeclaration; + } + + @Override + public int getNumberOfParams() { + return 0; + } + + @Override + public ResolvedParameterDeclaration getParam(int i) { + throw new UnsupportedOperationException("The default constructor has not parameters"); + } + + @Override + public String getName() { + return classDeclaration.getName(); + } + + @Override + public AccessSpecifier accessSpecifier() { + return AccessSpecifier.PUBLIC; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return Collections.emptyList(); + } + + @Override + public int getNumberOfSpecifiedExceptions() { + return 0; + } + + @Override + public ResolvedType getSpecifiedException(int index) { + throw new UnsupportedOperationException("The default constructor does not throw exceptions"); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/Helper.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/Helper.java new file mode 100644 index 000000000..d34e16412 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/Helper.java @@ -0,0 +1,85 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.*; + +import java.util.EnumSet; +import java.util.Optional; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; + +/** + * @author Federico Tomassetti + */ +class Helper { + + public static AccessSpecifier toAccessLevel(EnumSet<Modifier> modifiers) { + if (modifiers.contains(Modifier.PRIVATE)) { + return AccessSpecifier.PRIVATE; + } else if (modifiers.contains(Modifier.PROTECTED)) { + return AccessSpecifier.PROTECTED; + } else if (modifiers.contains(Modifier.PUBLIC)) { + return AccessSpecifier.PUBLIC; + } else { + return AccessSpecifier.DEFAULT; + } + } + + static String containerName(Node container) { + String packageName = getPackageName(container); + String className = getClassName("", container); + return packageName + + ((!packageName.isEmpty() && !className.isEmpty()) ? "." : "") + + className; + } + + static String getPackageName(Node container) { + if (container instanceof CompilationUnit) { + Optional<PackageDeclaration> p = ((CompilationUnit) container).getPackageDeclaration(); + if (p.isPresent()) { + return p.get().getName().toString(); + } + } else if (container != null) { + return getPackageName(container.getParentNode().orElse(null)); + } + return ""; + } + + static String getClassName(String base, Node container) { + if (container instanceof com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) { + String b = getClassName(base, container.getParentNode().orElse(null)); + String cn = ((com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) container).getName().getId(); + if (b.isEmpty()) { + return cn; + } else { + return b + "." + cn; + } + } else if (container instanceof com.github.javaparser.ast.body.EnumDeclaration) { + String b = getClassName(base, container.getParentNode().orElse(null)); + String cn = ((com.github.javaparser.ast.body.EnumDeclaration) container).getName().getId(); + if (b.isEmpty()) { + return cn; + } else { + return b + "." + cn; + } + } else if (container != null) { + return getClassName(base, container.getParentNode().orElse(null)); + } + return base; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnnotationDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnnotationDeclaration.java new file mode 100644 index 000000000..1f6c6f33f --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnnotationDeclaration.java @@ -0,0 +1,103 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.declarations; + +import com.github.javaparser.ast.body.AnnotationDeclaration; +import com.github.javaparser.ast.body.AnnotationMemberDeclaration; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserAnnotationDeclaration extends AbstractTypeDeclaration implements ResolvedAnnotationDeclaration { + + private com.github.javaparser.ast.body.AnnotationDeclaration wrappedNode; + private TypeSolver typeSolver; + + public JavaParserAnnotationDeclaration(AnnotationDeclaration wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + throw new UnsupportedOperationException(); + } + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasDirectlyAnnotation(String qualifiedName) { + throw new UnsupportedOperationException(); + } + + @Override + public String getPackageName() { + return Helper.getPackageName(wrappedNode); + } + + @Override + public String getClassName() { + return Helper.getClassName("", wrappedNode); + } + + @Override + public String getQualifiedName() { + String containerName = Helper.containerName(wrappedNode.getParentNode().orElse(null)); + if (containerName.isEmpty()) { + return wrappedNode.getName().getId(); + } else { + return containerName + "." + wrappedNode.getName(); + } + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + throw new UnsupportedOperationException("containerType is not supported for " + this.getClass().getCanonicalName()); + } + + @Override + public List<ResolvedAnnotationMemberDeclaration> getAnnotationMembers() { + return wrappedNode.getMembers().stream() + .filter(m -> m instanceof AnnotationMemberDeclaration) + .map(m -> new JavaParserAnnotationMemberDeclaration((AnnotationMemberDeclaration)m, typeSolver)) + .collect(Collectors.toList()); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnnotationMemberDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnnotationMemberDeclaration.java new file mode 100644 index 000000000..2a603daf8 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnnotationMemberDeclaration.java @@ -0,0 +1,40 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.declarations; + +import com.github.javaparser.ast.body.AnnotationMemberDeclaration; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.resolution.declarations.ResolvedAnnotationMemberDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +/** + * @author Federico Tomassetti + */ +public class JavaParserAnnotationMemberDeclaration implements ResolvedAnnotationMemberDeclaration { + + private com.github.javaparser.ast.body.AnnotationMemberDeclaration wrappedNode; + private TypeSolver typeSolver; + + public AnnotationMemberDeclaration getWrappedNode() { + return wrappedNode; + } + + public JavaParserAnnotationMemberDeclaration(AnnotationMemberDeclaration wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public Expression getDefaultValue() { + throw new UnsupportedOperationException(); + } + + @Override + public ResolvedType getType() { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + return wrappedNode.getNameAsString(); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnonymousClassDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnonymousClassDeclaration.java new file mode 100644 index 000000000..3d2cb8f69 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserAnonymousClassDeclaration.java @@ -0,0 +1,205 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.declarations; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * An anonymous class declaration representation. + */ +public class JavaParserAnonymousClassDeclaration extends AbstractClassDeclaration { + + private final TypeSolver typeSolver; + private final ObjectCreationExpr wrappedNode; + private final ResolvedTypeDeclaration superTypeDeclaration; + private final String name = "Anonymous-" + UUID.randomUUID(); + + public JavaParserAnonymousClassDeclaration(ObjectCreationExpr wrappedNode, + TypeSolver typeSolver) { + this.typeSolver = typeSolver; + this.wrappedNode = wrappedNode; + superTypeDeclaration = + JavaParserFactory.getContext(wrappedNode.getParentNode().get(), typeSolver) + .solveType(wrappedNode.getType().getName().getId(), typeSolver) + .getCorrespondingDeclaration(); + } + + public ResolvedTypeDeclaration getSuperTypeDeclaration() { + return superTypeDeclaration; + } + + public <T extends Node> List<T> findMembersOfKind(final Class<T> memberClass) { + if (wrappedNode.getAnonymousClassBody().isPresent()) { + return wrappedNode + .getAnonymousClassBody() + .get() + .stream() + .filter(node -> memberClass.isAssignableFrom(node.getClass())) + .map(memberClass::cast) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + public Context getContext() { + return JavaParserFactory.getContext(wrappedNode, typeSolver); + } + + @Override + protected ResolvedReferenceType object() { + return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver); + } + + @Override + public ResolvedReferenceType getSuperClass() { + return new ReferenceTypeImpl(superTypeDeclaration.asReferenceType(), typeSolver); + } + + @Override + public List<ResolvedReferenceType> getInterfaces() { + return + superTypeDeclaration + .asReferenceType().getAncestors() + .stream() + .filter(type -> type.getTypeDeclaration().isInterface()) + .collect(Collectors.toList()); + } + + @Override + public List<ResolvedConstructorDeclaration> getConstructors() { + return + findMembersOfKind(com.github.javaparser.ast.body.ConstructorDeclaration.class) + .stream() + .map(ctor -> new JavaParserConstructorDeclaration(this, ctor, typeSolver)) + .collect(Collectors.toList()); + } + + @Override + public AccessSpecifier accessSpecifier() { + return AccessSpecifier.PRIVATE; + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + return + ImmutableList. + <ResolvedReferenceType>builder() + .add(getSuperClass()) + .addAll(superTypeDeclaration.asReferenceType().getAncestors()) + .build(); + } + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + + List<JavaParserFieldDeclaration> myFields = + findMembersOfKind(com.github.javaparser.ast.body.FieldDeclaration.class) + .stream() + .flatMap(field -> + field.getVariables().stream() + .map(variable -> new JavaParserFieldDeclaration(variable, + typeSolver))) + .collect(Collectors.toList()); + + List<ResolvedFieldDeclaration> superClassFields = + getSuperClass().getTypeDeclaration().getAllFields(); + + List<ResolvedFieldDeclaration> interfaceFields = + getInterfaces().stream() + .flatMap(inteface -> inteface.getTypeDeclaration().getAllFields().stream()) + .collect(Collectors.toList()); + + return + ImmutableList + .<ResolvedFieldDeclaration>builder() + .addAll(myFields) + .addAll(superClassFields) + .addAll(interfaceFields) + .build(); + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + return + findMembersOfKind(com.github.javaparser.ast.body.MethodDeclaration.class) + .stream() + .map(method -> new JavaParserMethodDeclaration(method, typeSolver)) + .collect(Collectors.toSet()); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + return false; + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return false; + } + + @Override + public boolean hasDirectlyAnnotation(String qualifiedName) { + return false; + } + + @Override + public String getPackageName() { + return Helper.getPackageName(wrappedNode); + } + + @Override + public String getClassName() { + return Helper.getClassName("", wrappedNode); + } + + @Override + public String getQualifiedName() { + String containerName = Helper.containerName(wrappedNode.getParentNode().orElse(null)); + if (containerName.isEmpty()) { + return getName(); + } else { + return containerName + "." + getName(); + } + } + + @Override + public Set<ResolvedReferenceTypeDeclaration> internalTypes() { + return + findMembersOfKind(com.github.javaparser.ast.body.TypeDeclaration.class) + .stream() + .map(typeMember -> JavaParserFacade.get(typeSolver).getTypeDeclaration(typeMember)) + .collect(Collectors.toSet()); + } + + @Override + public String getName() { + return name; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return Lists.newArrayList(); + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + throw new UnsupportedOperationException("containerType is not supported for " + this.getClass().getCanonicalName()); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java new file mode 100644 index 000000000..bb9f91cc6 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java @@ -0,0 +1,397 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.*; +import com.github.javaparser.ast.expr.AnnotationExpr; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.resolution.UnsolvedSymbolException; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.LazyType; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; +import com.google.common.collect.ImmutableList; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserClassDeclaration extends AbstractClassDeclaration { + + /// + /// Fields + /// + + private TypeSolver typeSolver; + private com.github.javaparser.ast.body.ClassOrInterfaceDeclaration wrappedNode; + private JavaParserTypeAdapter<ClassOrInterfaceDeclaration> javaParserTypeAdapter; + + /// + /// Constructors + /// + + public JavaParserClassDeclaration(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration wrappedNode, + TypeSolver typeSolver) { + if (wrappedNode.isInterface()) { + throw new IllegalArgumentException("Interface given"); + } + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver); + } + + /// + /// Public methods: from Object + /// + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaParserClassDeclaration that = (JavaParserClassDeclaration) o; + + if (!wrappedNode.equals(that.wrappedNode)) return false; + + return true; + } + + @Override + public int hashCode() { + return wrappedNode.hashCode(); + } + + @Override + public String toString() { + return "JavaParserClassDeclaration{" + + "wrappedNode=" + wrappedNode + + '}'; + } + + /// + /// Public methods: fields + /// + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables(); + + getAncestors().forEach(ancestor -> ancestor.getTypeDeclaration().getAllFields().forEach(f -> { + fields.add(new ResolvedFieldDeclaration() { + + @Override + public AccessSpecifier accessSpecifier() { + return f.accessSpecifier(); + } + + @Override + public String getName() { + return f.getName(); + } + + @Override + public ResolvedType getType() { + return ancestor.useThisTypeParametersOnTheGivenType(f.getType()); + } + + @Override + public boolean isStatic() { + return f.isStatic(); + } + + @Override + public ResolvedTypeDeclaration declaringType() { + return f.declaringType(); + } + }); + })); + + return fields; + } + + /// + /// Public methods + /// + + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes) { + Context ctx = getContext(); + return ctx.solveMethod(name, parameterTypes, false, typeSolver); + } + + @Deprecated + public Context getContext() { + return JavaParserFactory.getContext(wrappedNode, typeSolver); + } + + public ResolvedType getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public ResolvedReferenceType getSuperClass() { + if (wrappedNode.getExtendedTypes().isEmpty()) { + return object(); + } else { + return toReferenceType(wrappedNode.getExtendedTypes().get(0)); + } + } + + @Override + public List<ResolvedReferenceType> getInterfaces() { + List<ResolvedReferenceType> interfaces = new ArrayList<>(); + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType t : wrappedNode.getImplementedTypes()) { + interfaces.add(toReferenceType(t)); + } + } + return interfaces; + } + + @Override + public List<ResolvedConstructorDeclaration> getConstructors() { + List<ResolvedConstructorDeclaration> declared = new LinkedList<>(); + for (BodyDeclaration<?> member : wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.ConstructorDeclaration) { + com.github.javaparser.ast.body.ConstructorDeclaration constructorDeclaration = (com.github.javaparser.ast.body.ConstructorDeclaration) member; + declared.add(new JavaParserConstructorDeclaration(this, constructorDeclaration, typeSolver)); + } + } + if (declared.isEmpty()) { + // If there are no constructors insert the default constructor + return ImmutableList.of(new DefaultConstructorDeclaration(this)); + } else { + return declared; + } + } + + @Override + public boolean hasDirectlyAnnotation(String canonicalName) { + for (AnnotationExpr annotationExpr : wrappedNode.getAnnotations()) { + if (solveType(annotationExpr.getName().getId(), typeSolver).getCorrespondingDeclaration().getQualifiedName().equals(canonicalName)) { + return true; + } + } + return false; + } + + @Override + public boolean isInterface() { + return wrappedNode.isInterface(); + } + + @Override + public String getPackageName() { + return javaParserTypeAdapter.getPackageName(); + } + + @Override + public String getClassName() { + return javaParserTypeAdapter.getClassName(); + } + + @Override + public String getQualifiedName() { + return javaParserTypeAdapter.getQualifiedName(); + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return javaParserTypeAdapter.isAssignableBy(other); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + return javaParserTypeAdapter.isAssignableBy(type); + } + + @Override + public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { + // TODO consider generic types + if (this.getQualifiedName().equals(other.getQualifiedName())) { + return true; + } + ResolvedClassDeclaration superclass = (ResolvedClassDeclaration) getSuperClass().getTypeDeclaration(); + if (superclass != null) { + // We want to avoid infinite recursion in case of Object having Object as ancestor + if (Object.class.getCanonicalName().equals(superclass.getQualifiedName())) { + return true; + } + if (superclass.canBeAssignedTo(other)) { + return true; + } + } + + if (this.wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType type : wrappedNode.getImplementedTypes()) { + ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type); + if (ancestor.canBeAssignedTo(other)) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isTypeParameter() { + return false; + } + + @Deprecated + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (this.wrappedNode.getName().getId().equals(name)) { + return SymbolReference.solved(this); + } + SymbolReference<ResolvedTypeDeclaration> ref = javaParserTypeAdapter.solveType(name, typeSolver); + if (ref.isSolved()) { + return ref; + } + + String prefix = wrappedNode.getName() + "."; + if (name.startsWith(prefix) && name.length() > prefix.length()) { + return new JavaParserClassDeclaration(this.wrappedNode, typeSolver).solveType(name.substring(prefix.length()), typeSolver); + } + + return getContext().getParent().solveType(name, typeSolver); + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + List<ResolvedReferenceType> ancestors = new ArrayList<>(); + + // We want to avoid infinite recursion in case of Object having Object as ancestor + if (!(Object.class.getCanonicalName().equals(getQualifiedName()))) { + ResolvedReferenceType superclass = getSuperClass(); + if (superclass != null) { + ancestors.add(superclass); + } + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType implemented : wrappedNode.getImplementedTypes()) { + ResolvedReferenceType ancestor = toReferenceType(implemented); + ancestors.add(ancestor); + } + } + } + + return ancestors; + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + Set<ResolvedMethodDeclaration> methods = new HashSet<>(); + for (BodyDeclaration<?> member : wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { + methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver)); + } + } + return methods; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return this.wrappedNode.getTypeParameters().stream().map( + (tp) -> new JavaParserTypeParameter(tp, typeSolver) + ).collect(Collectors.toList()); + } + + /** + * Returns the JavaParser node associated with this JavaParserClassDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.ClassOrInterfaceDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(wrappedNode.getModifiers()); + } + + /// + /// Protected methods + /// + + @Override + protected ResolvedReferenceType object() { + return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver); + } + + @Override + public Set<ResolvedReferenceTypeDeclaration> internalTypes() { + Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>(); + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member)); + } + } + return res; + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + return javaParserTypeAdapter.containerType(); + } + + /// + /// Private methods + /// + + private ResolvedReferenceType toReferenceType(ClassOrInterfaceType classOrInterfaceType) { + String className = classOrInterfaceType.getName().getId(); + if (classOrInterfaceType.getScope().isPresent()) { + // look for the qualified name (for example class of type Rectangle2D.Double) + className = classOrInterfaceType.getScope().get().toString() + "." + className; + } + SymbolReference<ResolvedTypeDeclaration> ref = solveType(className, typeSolver); + if (!ref.isSolved()) { + Optional<ClassOrInterfaceType> localScope = classOrInterfaceType.getScope(); + if (localScope.isPresent()) { + String localName = localScope.get().getName().getId() + "." + classOrInterfaceType.getName().getId(); + ref = solveType(localName, typeSolver); + } + } + if (!ref.isSolved()) { + throw new UnsolvedSymbolException(classOrInterfaceType.getName().getId()); + } + if (!classOrInterfaceType.getTypeArguments().isPresent()) { + return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), typeSolver); + } + List<ResolvedType> superClassTypeParameters = classOrInterfaceType.getTypeArguments().get() + .stream().map(ta -> new LazyType(v -> JavaParserFacade.get(typeSolver).convert(ta, ta))) + .collect(Collectors.toList()); + return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), superClassTypeParameters, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserConstructorDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserConstructorDeclaration.java new file mode 100644 index 000000000..e9500fed2 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserConstructorDeclaration.java @@ -0,0 +1,103 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.resolution.declarations.ResolvedClassDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedParameterDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserConstructorDeclaration implements ResolvedConstructorDeclaration { + + private ResolvedClassDeclaration classDeclaration; + private com.github.javaparser.ast.body.ConstructorDeclaration wrappedNode; + private TypeSolver typeSolver; + + JavaParserConstructorDeclaration(ResolvedClassDeclaration classDeclaration, com.github.javaparser.ast.body.ConstructorDeclaration wrappedNode, + TypeSolver typeSolver) { + this.classDeclaration = classDeclaration; + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public ResolvedClassDeclaration declaringType() { + return classDeclaration; + } + + @Override + public int getNumberOfParams() { + return this.wrappedNode.getParameters().size(); + } + + @Override + public ResolvedParameterDeclaration getParam(int i) { + if (i < 0 || i >= getNumberOfParams()) { + throw new IllegalArgumentException(String.format("No param with index %d. Number of params: %d", i, getNumberOfParams())); + } + return new JavaParserParameterDeclaration(wrappedNode.getParameters().get(i), typeSolver); + } + + @Override + public String getName() { + return this.classDeclaration.getName(); + } + + /** + * Returns the JavaParser node associated with this JavaParserConstructorDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.ConstructorDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(wrappedNode.getModifiers()); + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return this.wrappedNode.getTypeParameters().stream().map((astTp) -> new JavaParserTypeParameter(astTp, typeSolver)).collect(Collectors.toList()); + } + + @Override + public int getNumberOfSpecifiedExceptions() { + return wrappedNode.getThrownExceptions().size(); + } + + @Override + public ResolvedType getSpecifiedException(int index) { + if (index < 0 || index >= getNumberOfSpecifiedExceptions()) { + throw new IllegalArgumentException(String.format("No exception with index %d. Number of exceptions: %d", + index, getNumberOfSpecifiedExceptions())); + } + return JavaParserFacade.get(typeSolver) + .convert(wrappedNode.getThrownExceptions().get(index), wrappedNode); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumConstantDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumConstantDeclaration.java new file mode 100644 index 000000000..6f909582d --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumConstantDeclaration.java @@ -0,0 +1,59 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.body.EnumDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedEnumConstantDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserEnumConstantDeclaration implements ResolvedEnumConstantDeclaration { + + private TypeSolver typeSolver; + private com.github.javaparser.ast.body.EnumConstantDeclaration wrappedNode; + + public JavaParserEnumConstantDeclaration(com.github.javaparser.ast.body.EnumConstantDeclaration wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public ResolvedType getType() { + return new ReferenceTypeImpl(new JavaParserEnumDeclaration((EnumDeclaration) requireParentNode(wrappedNode), typeSolver), typeSolver); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + /** + * Returns the JavaParser node associated with this JavaParserEnumConstantDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.EnumConstantDeclaration getWrappedNode() { + return wrappedNode; + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java new file mode 100644 index 000000000..818c0604c --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java @@ -0,0 +1,350 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.EnumConstantDeclaration; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.resolution.MethodUsage; +import com.github.javaparser.resolution.UnsolvedSymbolException; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedArrayType; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametersMap; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionFactory; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; + +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserEnumDeclaration extends AbstractTypeDeclaration implements ResolvedEnumDeclaration { + + private TypeSolver typeSolver; + private com.github.javaparser.ast.body.EnumDeclaration wrappedNode; + private JavaParserTypeAdapter<com.github.javaparser.ast.body.EnumDeclaration> javaParserTypeAdapter; + + public JavaParserEnumDeclaration(com.github.javaparser.ast.body.EnumDeclaration wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver); + } + + @Override + public String toString() { + return "JavaParserEnumDeclaration{" + + "wrappedNode=" + wrappedNode + + '}'; + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + Set<ResolvedMethodDeclaration> methods = new HashSet<>(); + for (BodyDeclaration<?> member : wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { + methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver)); + } + } + return methods; + } + + public Context getContext() { + return JavaParserFactory.getContext(wrappedNode, typeSolver); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public boolean isField() { + return false; + } + + @Override + public boolean isParameter() { + return false; + } + + @Override + public boolean isType() { + return true; + } + + @Override + public boolean hasDirectlyAnnotation(String canonicalName) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { + String otherName = other.getQualifiedName(); + // Enums cannot be extended + if (otherName.equals(this.getQualifiedName())) { + return true; + } + if (otherName.equals(Enum.class.getCanonicalName())) { + return true; + } + // Enum implements Comparable and Serializable + if (otherName.equals(Comparable.class.getCanonicalName())) { + return true; + } + if (otherName.equals(Serializable.class.getCanonicalName())) { + return true; + } + if (otherName.equals(Object.class.getCanonicalName())) { + return true; + } + return false; + } + + @Override + public boolean isClass() { + return false; + } + + @Override + public boolean isInterface() { + return false; + } + + @Override + public String getPackageName() { + return javaParserTypeAdapter.getPackageName(); + } + + @Override + public String getClassName() { + return javaParserTypeAdapter.getClassName(); + } + + @Override + public String getQualifiedName() { + return javaParserTypeAdapter.getQualifiedName(); + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return javaParserTypeAdapter.isAssignableBy(other); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + return javaParserTypeAdapter.isAssignableBy(type); + } + + @Override + public boolean isTypeParameter() { + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaParserEnumDeclaration that = (JavaParserEnumDeclaration) o; + + if (!wrappedNode.equals(that.wrappedNode)) return false; + + return true; + } + + @Override + public int hashCode() { + return wrappedNode.hashCode(); + } + + @Deprecated + public Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> parameterTypes, + TypeSolver typeSolver, Context invokationContext, List<ResolvedType> typeParameterValues) { + if (name.equals("values") && parameterTypes.isEmpty()) { + return Optional.of(new ValuesMethod(this, typeSolver).getUsage(null)); + } + // TODO add methods inherited from Enum + return getContext().solveMethodAsUsage(name, parameterTypes, typeSolver); + } + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables(); + + if (this.wrappedNode.getEntries() != null) { + for (EnumConstantDeclaration member : this.wrappedNode.getEntries()) { + fields.add(new JavaParserFieldDeclaration(member, typeSolver)); + } + } + + return fields; + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + List<ResolvedReferenceType> ancestors = new ArrayList<>(); + ResolvedReferenceType enumClass = ReflectionFactory.typeUsageFor(Enum.class, typeSolver).asReferenceType(); + ResolvedTypeParameterDeclaration eTypeParameter = enumClass.getTypeDeclaration().getTypeParameters().get(0); + enumClass = enumClass.deriveTypeParameters(new ResolvedTypeParametersMap.Builder().setValue(eTypeParameter, new ReferenceTypeImpl(this, typeSolver)).build()); + ancestors.add(enumClass); + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType implementedType : wrappedNode.getImplementedTypes()) { + SymbolReference<ResolvedTypeDeclaration> implementedDeclRef = new SymbolSolver(typeSolver).solveTypeInType(this, implementedType.getName().getId()); + if (!implementedDeclRef.isSolved()) { + throw new UnsolvedSymbolException(implementedType.getName().getId()); + } + ancestors.add(new ReferenceTypeImpl((ResolvedReferenceTypeDeclaration) implementedDeclRef.getCorrespondingDeclaration(), typeSolver)); + } + } + return ancestors; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return Collections.emptyList(); + } + + /** + * Returns the JavaParser node associated with this JavaParserEnumDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.EnumDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public List<ResolvedEnumConstantDeclaration> getEnumConstants() { + return wrappedNode.getEntries().stream() + .map(entry -> new JavaParserEnumConstantDeclaration(entry, typeSolver)) + .collect(Collectors.toList()); + } + + // Needed by ContextHelper + public static class ValuesMethod implements ResolvedMethodDeclaration { + + private JavaParserEnumDeclaration enumDeclaration; + private TypeSolver typeSolver; + + public ValuesMethod(JavaParserEnumDeclaration enumDeclaration, TypeSolver typeSolver) { + this.enumDeclaration = enumDeclaration; + this.typeSolver = typeSolver; + } + + @Override + public ResolvedReferenceTypeDeclaration declaringType() { + return enumDeclaration; + } + + @Override + public ResolvedType getReturnType() { + return new ResolvedArrayType(new ReferenceTypeImpl(enumDeclaration, typeSolver)); + } + + @Override + public int getNumberOfParams() { + return 0; + } + + @Override + public ResolvedParameterDeclaration getParam(int i) { + throw new UnsupportedOperationException(); + } + + public MethodUsage getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + public MethodUsage resolveTypeVariables(Context context, List<ResolvedType> parameterTypes) { + return new MethodUsage(this); + } + + @Override + public boolean isAbstract() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDefaultMethod() { + return false; + } + + @Override + public boolean isStatic() { + return false; + } + + @Override + public String getName() { + return "values"; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return Collections.emptyList(); + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(enumDeclaration.getWrappedNode().getModifiers()); + } + + @Override + public int getNumberOfSpecifiedExceptions() { + return 0; + } + + @Override + public ResolvedType getSpecifiedException(int index) { + throw new UnsupportedOperationException("The values method of an enum does not throw any exception"); + } + } + + @Override + public AccessSpecifier accessSpecifier() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<ResolvedReferenceTypeDeclaration> internalTypes() { + Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>(); + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member)); + } + } + return res; + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + return javaParserTypeAdapter.containerType(); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserFieldDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserFieldDeclaration.java new file mode 100644 index 000000000..1c9e00511 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserFieldDeclaration.java @@ -0,0 +1,121 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.body.EnumConstantDeclaration; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparser.Navigator; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; + +import java.util.Optional; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserFieldDeclaration implements ResolvedFieldDeclaration { + + private VariableDeclarator variableDeclarator; + private com.github.javaparser.ast.body.FieldDeclaration wrappedNode; + private EnumConstantDeclaration enumConstantDeclaration; + private TypeSolver typeSolver; + + public JavaParserFieldDeclaration(VariableDeclarator variableDeclarator, TypeSolver typeSolver) { + if (typeSolver == null) { + throw new IllegalArgumentException("typeSolver should not be null"); + } + this.variableDeclarator = variableDeclarator; + this.typeSolver = typeSolver; + if (!(requireParentNode(variableDeclarator) instanceof com.github.javaparser.ast.body.FieldDeclaration)) { + throw new IllegalStateException(requireParentNode(variableDeclarator).getClass().getCanonicalName()); + } + this.wrappedNode = (com.github.javaparser.ast.body.FieldDeclaration) requireParentNode(variableDeclarator); + } + + public JavaParserFieldDeclaration(EnumConstantDeclaration enumConstantDeclaration, TypeSolver typeSolver) { + if (typeSolver == null) { + throw new IllegalArgumentException("typeSolver should not be null"); + } + this.enumConstantDeclaration = enumConstantDeclaration; + this.typeSolver = typeSolver; + } + + @Override + public ResolvedType getType() { + if (enumConstantDeclaration != null) { + com.github.javaparser.ast.body.EnumDeclaration enumDeclaration = (com.github.javaparser.ast.body.EnumDeclaration) requireParentNode(enumConstantDeclaration); + return new ReferenceTypeImpl(new JavaParserEnumDeclaration(enumDeclaration, typeSolver), typeSolver); + } + return JavaParserFacade.get(typeSolver).convert(variableDeclarator.getType(), wrappedNode); + } + + @Override + public String getName() { + if (enumConstantDeclaration != null) { + return enumConstantDeclaration.getName().getId(); + } else { + return variableDeclarator.getName().getId(); + } + } + + @Override + public boolean isStatic() { + return wrappedNode.getModifiers().contains(Modifier.STATIC); + } + + @Override + public boolean isField() { + return true; + } + + /** + * Returns the JavaParser node associated with this JavaParserFieldDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.FieldDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public String toString() { + return "JPField{" + getName() + "}"; + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(wrappedNode.getModifiers()); + } + + @Override + public ResolvedTypeDeclaration declaringType() { + Optional<com.github.javaparser.ast.body.TypeDeclaration> typeDeclaration = wrappedNode.findParent(com.github.javaparser.ast.body.TypeDeclaration.class); + if (typeDeclaration.isPresent()) { + return JavaParserFacade.get(typeSolver).getTypeDeclaration(typeDeclaration.get()); + } + throw new IllegalStateException(); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserInterfaceDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserInterfaceDeclaration.java new file mode 100644 index 000000000..34955a0c0 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserInterfaceDeclaration.java @@ -0,0 +1,335 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.expr.AnnotationExpr; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.resolution.UnsolvedSymbolException; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.LazyType; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserInterfaceDeclaration extends AbstractTypeDeclaration implements ResolvedInterfaceDeclaration { + + private TypeSolver typeSolver; + private ClassOrInterfaceDeclaration wrappedNode; + private JavaParserTypeAdapter<ClassOrInterfaceDeclaration> javaParserTypeAdapter; + + public JavaParserInterfaceDeclaration(ClassOrInterfaceDeclaration wrappedNode, TypeSolver typeSolver) { + if (!wrappedNode.isInterface()) { + throw new IllegalArgumentException(); + } + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver); + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + Set<ResolvedMethodDeclaration> methods = new HashSet<>(); + for (BodyDeclaration<?> member : wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { + methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver)); + } + } + return methods; + } + + public Context getContext() { + return JavaParserFactory.getContext(wrappedNode, typeSolver); + } + + public ResolvedType getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaParserInterfaceDeclaration that = (JavaParserInterfaceDeclaration) o; + + if (!wrappedNode.equals(that.wrappedNode)) return false; + + return true; + } + + @Override + public int hashCode() { + return wrappedNode.hashCode(); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public ResolvedInterfaceDeclaration asInterface() { + return this; + } + + @Override + public boolean hasDirectlyAnnotation(String canonicalName) { + for (AnnotationExpr annotationExpr : wrappedNode.getAnnotations()) { + if (solveType(annotationExpr.getName().getId(), typeSolver).getCorrespondingDeclaration().getQualifiedName().equals(canonicalName)) { + return true; + } + } + return false; + } + + @Override + public boolean isInterface() { + return true; + } + + @Override + public List<ResolvedReferenceType> getInterfacesExtended() { + List<ResolvedReferenceType> interfaces = new ArrayList<>(); + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType t : wrappedNode.getImplementedTypes()) { + interfaces.add(new ReferenceTypeImpl(solveType(t.getName().getId(), typeSolver).getCorrespondingDeclaration().asInterface(), typeSolver)); + } + } + return interfaces; + } + + @Override + public String getPackageName() { + return javaParserTypeAdapter.getPackageName(); + } + + @Override + public String getClassName() { + return javaParserTypeAdapter.getClassName(); + } + + @Override + public String getQualifiedName() { + return javaParserTypeAdapter.getQualifiedName(); + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return javaParserTypeAdapter.isAssignableBy(other); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + return javaParserTypeAdapter.isAssignableBy(type); + } + + @Override + public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { + // TODO consider generic types + if (this.getQualifiedName().equals(other.getQualifiedName())) { + return true; + } + if (this.wrappedNode.getExtendedTypes() != null) { + for (ClassOrInterfaceType type : wrappedNode.getExtendedTypes()) { + ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type); + if (ancestor.canBeAssignedTo(other)) { + return true; + } + } + } + + if (this.wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType type : wrappedNode.getImplementedTypes()) { + ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type); + if (ancestor.canBeAssignedTo(other)) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isTypeParameter() { + return false; + } + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables(); + + getAncestors().forEach(ancestor -> ancestor.getTypeDeclaration().getAllFields().forEach(f -> { + fields.add(new ResolvedFieldDeclaration() { + + @Override + public AccessSpecifier accessSpecifier() { + return f.accessSpecifier(); + } + + @Override + public String getName() { + return f.getName(); + } + + @Override + public ResolvedType getType() { + return ancestor.useThisTypeParametersOnTheGivenType(f.getType()); + } + + @Override + public boolean isStatic() { + return f.isStatic(); + } + + @Override + public ResolvedTypeDeclaration declaringType() { + return f.declaringType(); + } + }); + })); + + return fields; + } + + + @Override + public String toString() { + return "JavaParserInterfaceDeclaration{" + + "wrappedNode=" + wrappedNode + + '}'; + } + + @Deprecated + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (this.wrappedNode.getName().getId().equals(name)) { + return SymbolReference.solved(this); + } + SymbolReference<ResolvedTypeDeclaration> ref = javaParserTypeAdapter.solveType(name, typeSolver); + if (ref.isSolved()) { + return ref; + } + + String prefix = wrappedNode.getName() + "."; + if (name.startsWith(prefix) && name.length() > prefix.length()) { + return new JavaParserInterfaceDeclaration(this.wrappedNode, typeSolver).solveType(name.substring(prefix.length()), typeSolver); + } + + return getContext().getParent().solveType(name, typeSolver); + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + List<ResolvedReferenceType> ancestors = new ArrayList<>(); + if (wrappedNode.getExtendedTypes() != null) { + for (ClassOrInterfaceType extended : wrappedNode.getExtendedTypes()) { + ancestors.add(toReferenceType(extended)); + } + } + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType implemented : wrappedNode.getImplementedTypes()) { + ancestors.add(toReferenceType(implemented)); + } + } + return ancestors; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + if (this.wrappedNode.getTypeParameters() == null) { + return Collections.emptyList(); + } else { + return this.wrappedNode.getTypeParameters().stream().map( + (tp) -> new JavaParserTypeParameter(tp, typeSolver) + ).collect(Collectors.toList()); + } + } + + /** + * Returns the JavaParser node associated with this JavaParserInterfaceDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public ClassOrInterfaceDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(wrappedNode.getModifiers()); + } + + @Override + public Set<ResolvedReferenceTypeDeclaration> internalTypes() { + Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>(); + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member)); + } + } + return res; + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + return javaParserTypeAdapter.containerType(); + } + + /// + /// Private methods + /// + + private ResolvedReferenceType toReferenceType(ClassOrInterfaceType classOrInterfaceType) { + SymbolReference<? extends ResolvedTypeDeclaration> ref = null; + if (classOrInterfaceType.toString().indexOf('.') > -1) { + ref = typeSolver.tryToSolveType(classOrInterfaceType.toString()); + } + if (ref == null || !ref.isSolved()) { + ref = solveType(classOrInterfaceType.toString(), typeSolver); + } + if (!ref.isSolved()) { + ref = solveType(classOrInterfaceType.getName().getId(), typeSolver); + } + if (!ref.isSolved()) { + throw new UnsolvedSymbolException(classOrInterfaceType.getName().getId()); + } + if (!classOrInterfaceType.getTypeArguments().isPresent()) { + return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), typeSolver); + } + List<ResolvedType> superClassTypeParameters = classOrInterfaceType.getTypeArguments().get() + .stream().map(ta -> new LazyType(v -> JavaParserFacade.get(typeSolver).convert(ta, ta))) + .collect(Collectors.toList()); + return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), superClassTypeParameters, typeSolver); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserMethodDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserMethodDeclaration.java new file mode 100644 index 000000000..4f3cb3569 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserMethodDeclaration.java @@ -0,0 +1,167 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.resolution.MethodUsage; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedParameterDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.declarations.common.MethodDeclarationCommonLogic; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserMethodDeclaration implements ResolvedMethodDeclaration { + + private com.github.javaparser.ast.body.MethodDeclaration wrappedNode; + private TypeSolver typeSolver; + + public JavaParserMethodDeclaration(com.github.javaparser.ast.body.MethodDeclaration wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public String toString() { + return "JavaParserMethodDeclaration{" + + "wrappedNode=" + wrappedNode + + ", typeSolver=" + typeSolver + + '}'; + } + + @Override + public ResolvedReferenceTypeDeclaration declaringType() { + if (requireParentNode(wrappedNode) instanceof ObjectCreationExpr) { + ObjectCreationExpr parentNode = (ObjectCreationExpr) requireParentNode(wrappedNode); + return new JavaParserAnonymousClassDeclaration(parentNode, typeSolver); + } + return JavaParserFactory.toTypeDeclaration(requireParentNode(wrappedNode), typeSolver); + } + + @Override + public ResolvedType getReturnType() { + return JavaParserFacade.get(typeSolver).convert(wrappedNode.getType(), getContext()); + } + + @Override + public int getNumberOfParams() { + return wrappedNode.getParameters().size(); + } + + @Override + public ResolvedParameterDeclaration getParam(int i) { + if (i < 0 || i >= getNumberOfParams()) { + throw new IllegalArgumentException(String.format("No param with index %d. Number of params: %d", i, getNumberOfParams())); + } + return new JavaParserParameterDeclaration(wrappedNode.getParameters().get(i), typeSolver); + } + + public MethodUsage getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + public MethodUsage resolveTypeVariables(Context context, List<ResolvedType> parameterTypes) { + return new MethodDeclarationCommonLogic(this, typeSolver).resolveTypeVariables(context, parameterTypes); + } + + private Context getContext() { + return JavaParserFactory.getContext(wrappedNode, typeSolver); + } + + @Override + public boolean isAbstract() { + return !wrappedNode.getBody().isPresent(); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public boolean isField() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isParameter() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isType() { + throw new UnsupportedOperationException(); + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return this.wrappedNode.getTypeParameters().stream().map((astTp) -> new JavaParserTypeParameter(astTp, typeSolver)).collect(Collectors.toList()); + } + + @Override + public boolean isDefaultMethod() { + return wrappedNode.isDefault(); + } + + @Override + public boolean isStatic() { + return wrappedNode.isStatic(); + } + + /** + * Returns the JavaParser node associated with this JavaParserMethodDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.MethodDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(wrappedNode.getModifiers()); + } + + @Override + public int getNumberOfSpecifiedExceptions() { + return wrappedNode.getThrownExceptions().size(); + } + + @Override + public ResolvedType getSpecifiedException(int index) { + if (index < 0 || index >= getNumberOfSpecifiedExceptions()) { + throw new IllegalArgumentException(String.format("No exception with index %d. Number of exceptions: %d", + index, getNumberOfSpecifiedExceptions())); + } + return JavaParserFacade.get(typeSolver).convert(wrappedNode.getThrownExceptions() + .get(index), wrappedNode); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserParameterDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserParameterDeclaration.java new file mode 100644 index 000000000..cba7d32b1 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserParameterDeclaration.java @@ -0,0 +1,100 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.type.UnknownType; +import com.github.javaparser.resolution.declarations.ResolvedParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedArrayType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.javaparsermodel.contexts.LambdaExprContext; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.resolution.Value; + +import java.util.Optional; + +/** + * @author Federico Tomassetti + */ +public class JavaParserParameterDeclaration implements ResolvedParameterDeclaration { + + private Parameter wrappedNode; + private TypeSolver typeSolver; + + public JavaParserParameterDeclaration(Parameter wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public boolean isField() { + return false; + } + + @Override + public boolean isParameter() { + return true; + } + + @Override + public boolean isVariadic() { + return wrappedNode.isVarArgs(); + } + + @Override + public boolean isType() { + throw new UnsupportedOperationException(); + } + + @Override + public ResolvedType getType() { + if (wrappedNode.getType() instanceof UnknownType && JavaParserFactory.getContext(wrappedNode, typeSolver) instanceof LambdaExprContext) { + Optional<Value> value = JavaParserFactory.getContext(wrappedNode, typeSolver).solveSymbolAsValue(wrappedNode.getNameAsString(), typeSolver); + if (value.isPresent()) { + return value.get().getType(); + } + } + ResolvedType res = JavaParserFacade.get(typeSolver).convert(wrappedNode.getType(), wrappedNode); + if (isVariadic()) { + res = new ResolvedArrayType(res); + } + return res; + } + + @Override + public ResolvedParameterDeclaration asParameter() { + return this; + } + + /** + * Returns the JavaParser node associated with this JavaParserParameterDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public Parameter getWrappedNode() { + return wrappedNode; + } + + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserSymbolDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserSymbolDeclaration.java new file mode 100644 index 000000000..f1f1ffb69 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserSymbolDeclaration.java @@ -0,0 +1,171 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedArrayType; +import com.github.javaparser.resolution.types.ResolvedPrimitiveType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserSymbolDeclaration implements ResolvedValueDeclaration { + + private String name; + private Node wrappedNode; + private boolean field; + private boolean parameter; + private boolean variable; + private TypeSolver typeSolver; + + private JavaParserSymbolDeclaration(Node wrappedNode, String name, TypeSolver typeSolver, boolean field, boolean parameter, boolean variable) { + this.name = name; + this.wrappedNode = wrappedNode; + this.field = field; + this.variable = variable; + this.parameter = parameter; + this.typeSolver = typeSolver; + } + + public static JavaParserFieldDeclaration field(VariableDeclarator wrappedNode, TypeSolver typeSolver) { + return new JavaParserFieldDeclaration(wrappedNode, typeSolver); + } + + public static JavaParserParameterDeclaration parameter(Parameter parameter, TypeSolver typeSolver) { + return new JavaParserParameterDeclaration(parameter, typeSolver); + } + + public static JavaParserSymbolDeclaration localVar(VariableDeclarator variableDeclarator, TypeSolver typeSolver) { + return new JavaParserSymbolDeclaration(variableDeclarator, variableDeclarator.getName().getId(), typeSolver, false, false, true); + } + + public static int getParamPos(Parameter parameter) { + int pos = 0; + for (Node node : requireParentNode(parameter).getChildNodes()) { + if (node == parameter) { + return pos; + } else if (node instanceof Parameter) { + pos++; + } + } + return pos; + } + + public static int getParamPos(Node node) { + if (requireParentNode(node) instanceof MethodCallExpr) { + MethodCallExpr call = (MethodCallExpr) requireParentNode(node); + for (int i = 0; i < call.getArguments().size(); i++) { + if (call.getArguments().get(i) == node) return i; + } + throw new IllegalStateException(); + } + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return "JavaParserSymbolDeclaration{" + + "name='" + name + '\'' + + ", wrappedNode=" + wrappedNode + + '}'; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isField() { + return field; + } + + @Override + public boolean isParameter() { + return parameter; + } + + @Override + public boolean isType() { + return false; + } + + @Override + public ResolvedType getType() { + if (wrappedNode instanceof Parameter) { + Parameter parameter = (Parameter) wrappedNode; + if (requireParentNode(wrappedNode) instanceof LambdaExpr) { + int pos = getParamPos(parameter); + ResolvedType lambdaType = JavaParserFacade.get(typeSolver).getType(requireParentNode(wrappedNode)); + + // TODO understand from the context to which method this corresponds + //MethodDeclaration methodDeclaration = JavaParserFacade.get(typeSolver).getMethodCalled + //MethodDeclaration methodCalled = JavaParserFacade.get(typeSolver).solve() + throw new UnsupportedOperationException(wrappedNode.getClass().getCanonicalName()); + } else { + final ResolvedType rawType; + if (parameter.getType() instanceof com.github.javaparser.ast.type.PrimitiveType) { + rawType = ResolvedPrimitiveType.byName(((com.github.javaparser.ast.type.PrimitiveType) parameter.getType()).getType().name()); + } else { + rawType = JavaParserFacade.get(typeSolver).convertToUsage(parameter.getType(), wrappedNode); + } + if (parameter.isVarArgs()) { + return new ResolvedArrayType(rawType); + } + return rawType; + } + } else if (wrappedNode instanceof VariableDeclarator) { + VariableDeclarator variableDeclarator = (VariableDeclarator) wrappedNode; + if (requireParentNode(wrappedNode) instanceof VariableDeclarationExpr) { + return JavaParserFacade.get(typeSolver).convert(variableDeclarator.getType(), JavaParserFactory.getContext(wrappedNode, typeSolver)); + } else if (requireParentNode(wrappedNode) instanceof FieldDeclaration) { + return JavaParserFacade.get(typeSolver).convert(variableDeclarator.getType(), JavaParserFactory.getContext(wrappedNode, typeSolver)); + } + } + throw new UnsupportedOperationException(wrappedNode.getClass().getCanonicalName()); + } + + @Override + public ResolvedTypeDeclaration asType() { + throw new UnsupportedOperationException(this.getClass().getCanonicalName() + ": wrapping " + this.getWrappedNode().getClass().getCanonicalName()); + } + + /** + * Returns the JavaParser node associated with this JavaParserSymbolDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public Node getWrappedNode() { + return wrappedNode; + } + + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeAdapter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeAdapter.java new file mode 100644 index 000000000..198083f7a --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeAdapter.java @@ -0,0 +1,140 @@ +package com.github.javaparser.symbolsolver.javaparsermodel.declarations; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.EnumDeclaration; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.nodeTypes.NodeWithMembers; +import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName; +import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters; +import com.github.javaparser.ast.type.TypeParameter; +import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserTypeAdapter<T extends Node & NodeWithSimpleName<T> & NodeWithMembers<T>> { + + private T wrappedNode; + private TypeSolver typeSolver; + + public JavaParserTypeAdapter(T wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + public String getPackageName() { + return Helper.getPackageName(wrappedNode); + } + + public String getClassName() { + return Helper.getClassName("", wrappedNode); + } + + public String getQualifiedName() { + String containerName = Helper.containerName(getParentNode(wrappedNode)); + if (containerName.isEmpty()) { + return wrappedNode.getName().getId(); + } else { + return containerName + "." + wrappedNode.getName().getId(); + } + } + + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + List<ResolvedReferenceType> ancestorsOfOther = other.getAllAncestors(); + ancestorsOfOther.add(new ReferenceTypeImpl(other, typeSolver)); + for (ResolvedReferenceType ancestorOfOther : ancestorsOfOther) { + if (ancestorOfOther.getQualifiedName().equals(this.getQualifiedName())) { + return true; + } + } + return false; + } + + public boolean isAssignableBy(ResolvedType type) { + if (type.isNull()) { + return true; + } + if (type.isReferenceType()) { + ResolvedReferenceTypeDeclaration other = typeSolver.solveType(type.describe()); + return isAssignableBy(other); + } else { + throw new UnsupportedOperationException(); + } + } + + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if(wrappedNode instanceof NodeWithTypeParameters<?>) { + NodeList<TypeParameter> typeParameters = ((NodeWithTypeParameters<?>) wrappedNode).getTypeParameters(); + for (com.github.javaparser.ast.type.TypeParameter typeParameter : typeParameters) { + if (typeParameter.getName().getId().equals(name)) { + return SymbolReference.solved(new JavaParserTypeVariableDeclaration(typeParameter, typeSolver)); + } + } + } + + // Internal classes + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + com.github.javaparser.ast.body.TypeDeclaration<?> internalType = (com.github.javaparser.ast.body.TypeDeclaration<?>) member; + String prefix = internalType.getName() + "."; + if (internalType.getName().getId().equals(name)) { + if (internalType instanceof ClassOrInterfaceDeclaration) { + return SymbolReference.solved(new JavaParserClassDeclaration((com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) internalType, typeSolver)); + } else if (internalType instanceof EnumDeclaration) { + return SymbolReference.solved(new JavaParserEnumDeclaration((com.github.javaparser.ast.body.EnumDeclaration) internalType, typeSolver)); + } else { + throw new UnsupportedOperationException(); + } + } else if (name.startsWith(prefix) && name.length() > prefix.length()) { + if (internalType instanceof ClassOrInterfaceDeclaration) { + return new JavaParserClassDeclaration((com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) internalType, typeSolver).solveType(name.substring(prefix.length()), typeSolver); + } else if (internalType instanceof EnumDeclaration) { + return new SymbolSolver(typeSolver).solveTypeInType(new JavaParserEnumDeclaration((com.github.javaparser.ast.body.EnumDeclaration) internalType, typeSolver), name.substring(prefix.length())); + } else { + throw new UnsupportedOperationException(); + } + } + } + } + return SymbolReference.unsolved(ResolvedTypeDeclaration.class); + } + + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + return wrappedNode + .getParentNode() + .map(node -> JavaParserFactory.toTypeDeclaration(node, typeSolver)); + } + + public List<ResolvedFieldDeclaration> getFieldsForDeclaredVariables() { + List<ResolvedFieldDeclaration> fields = new ArrayList<>(); + if (wrappedNode.getMembers() != null) { + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.FieldDeclaration) { + com.github.javaparser.ast.body.FieldDeclaration field = (com.github.javaparser.ast.body.FieldDeclaration) member; + for (VariableDeclarator vd : field.getVariables()) { + fields.add(new JavaParserFieldDeclaration(vd, typeSolver)); + } + } + } + } + return fields; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java new file mode 100644 index 000000000..0d1f42e68 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java @@ -0,0 +1,223 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.resolution.declarations.*; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; + +/** + * @author Federico Tomassetti + */ +public class JavaParserTypeParameter extends AbstractTypeDeclaration implements ResolvedTypeParameterDeclaration { + + private com.github.javaparser.ast.type.TypeParameter wrappedNode; + private TypeSolver typeSolver; + + public JavaParserTypeParameter(com.github.javaparser.ast.type.TypeParameter wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + return Collections.emptySet(); + } + + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes) { + return getContext().solveMethod(name, parameterTypes, false, typeSolver); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof JavaParserTypeParameter)) return false; + + JavaParserTypeParameter that = (JavaParserTypeParameter) o; + + if (wrappedNode != null ? !wrappedNode.equals(that.wrappedNode) : that.wrappedNode != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = wrappedNode != null ? wrappedNode.hashCode() : 0; + result = 31 * result + (typeSolver != null ? typeSolver.hashCode() : 0); + return result; + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return isAssignableBy(new ReferenceTypeImpl(other, typeSolver)); + } + + @Override + public String getContainerQualifiedName() { + ResolvedTypeParametrizable container = getContainer(); + if (container instanceof ResolvedReferenceTypeDeclaration) { + return ((ResolvedReferenceTypeDeclaration) container).getQualifiedName(); + } else if (container instanceof JavaParserConstructorDeclaration) { + return ((JavaParserConstructorDeclaration) container).getQualifiedSignature(); + } else { + return ((JavaParserMethodDeclaration) container).getQualifiedSignature(); + } + } + + @Override + public String getContainerId() { + ResolvedTypeParametrizable container = getContainer(); + if (container instanceof ResolvedReferenceTypeDeclaration) { + return ((ResolvedReferenceTypeDeclaration) container).getId(); + } else if (container instanceof JavaParserConstructorDeclaration) { + return ((JavaParserConstructorDeclaration) container).getQualifiedSignature(); + } else { + return ((JavaParserMethodDeclaration) container).getQualifiedSignature(); + } + } + + @Override + public ResolvedTypeParametrizable getContainer() { + Node parentNode = requireParentNode(wrappedNode); + if (parentNode instanceof com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) { + com.github.javaparser.ast.body.ClassOrInterfaceDeclaration jpTypeDeclaration = (com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) parentNode; + return JavaParserFacade.get(typeSolver).getTypeDeclaration(jpTypeDeclaration); + } else if (parentNode instanceof com.github.javaparser.ast.body.ConstructorDeclaration){ + com.github.javaparser.ast.body.ConstructorDeclaration jpConstructorDeclaration = (com.github.javaparser.ast.body.ConstructorDeclaration) parentNode; + Optional<ClassOrInterfaceDeclaration> jpTypeDeclaration = jpConstructorDeclaration.getAncestorOfType(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration.class); + if (jpTypeDeclaration.isPresent()) { + ResolvedReferenceTypeDeclaration typeDeclaration = JavaParserFacade.get(typeSolver).getTypeDeclaration(jpTypeDeclaration.get()); + if (typeDeclaration.isClass()) { + return new JavaParserConstructorDeclaration(typeDeclaration.asClass(), jpConstructorDeclaration, typeSolver); + } + } + } else { + com.github.javaparser.ast.body.MethodDeclaration jpMethodDeclaration = (com.github.javaparser.ast.body.MethodDeclaration) parentNode; + return new JavaParserMethodDeclaration(jpMethodDeclaration, typeSolver); + } + throw new UnsupportedOperationException(); + } + + @Override + public String getQualifiedName() { + return String.format("%s.%s", getContainerQualifiedName(), getName()); + } + + @Override + public List<Bound> getBounds() { + return wrappedNode.getTypeBound().stream().map((astB) -> toBound(astB, typeSolver)).collect(Collectors.toList()); + } + + private Bound toBound(ClassOrInterfaceType classOrInterfaceType, TypeSolver typeSolver) { + ResolvedType type = JavaParserFacade.get(typeSolver).convertToUsage(classOrInterfaceType, classOrInterfaceType); + return Bound.extendsBound(type); + } + + public Context getContext() { + throw new UnsupportedOperationException(); + } + + public ResolvedType getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + throw new UnsupportedOperationException(); + } + + @Override + public ResolvedFieldDeclaration getField(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasField(String name) { + return false; + } + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + return new ArrayList<>(); + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isTypeParameter() { + return true; + } + + @Override + public boolean hasDirectlyAnnotation(String canonicalName) { + throw new UnsupportedOperationException(); + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return Collections.emptyList(); + } + + /** + * Returns the JavaParser node associated with this JavaParserTypeParameter. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.type.TypeParameter getWrappedNode() { + return wrappedNode; + } + + @Override + public String toString() { + return "JPTypeParameter(" + wrappedNode.getName() + ", bounds=" + wrappedNode.getTypeBound() + ")"; + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + ResolvedTypeParametrizable container = getContainer(); + if (container instanceof ResolvedReferenceTypeDeclaration) { + return Optional.of((ResolvedReferenceTypeDeclaration) container); + } + return Optional.empty(); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeVariableDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeVariableDeclaration.java new file mode 100644 index 000000000..a602ebf19 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeVariableDeclaration.java @@ -0,0 +1,187 @@ +/* + * 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.declarations; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.type.TypeParameter; +import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.core.resolution.Context; +import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @author Federico Tomassetti + */ +public class JavaParserTypeVariableDeclaration extends AbstractTypeDeclaration { + + private TypeParameter wrappedNode; + private TypeSolver typeSolver; + + public JavaParserTypeVariableDeclaration(TypeParameter wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return isAssignableBy(new ReferenceTypeImpl(other, typeSolver)); + } + + @Override + public String getPackageName() { + return Helper.getPackageName(wrappedNode); + } + + @Override + public String getClassName() { + return Helper.getClassName("", wrappedNode); + } + + @Override + public String getQualifiedName() { + return getName(); + } + + public Context getContext() { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "JavaParserTypeVariableDeclaration{" + + wrappedNode.getName() + + '}'; + } + + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes) { + throw new UnsupportedOperationException(); + } + + public ResolvedType getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + if (type.isTypeVariable()) { + throw new UnsupportedOperationException("Is this type variable declaration assignable by " + type.describe()); + } else { + throw new UnsupportedOperationException("Is this type variable declaration assignable by " + type); + } + } + + @Override + public boolean isTypeParameter() { + return true; + } + + @Override + public ResolvedFieldDeclaration getField(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasField(String name) { + return false; + } + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + return new ArrayList<>(); + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + return Collections.emptySet(); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public boolean isField() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isParameter() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isType() { + return true; + } + + @Override + public boolean hasDirectlyAnnotation(String canonicalName) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isClass() { + return false; + } + + @Override + public boolean isInterface() { + return false; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return Collections.emptyList(); + } + + public ResolvedTypeParameterDeclaration asTypeParameter() { + return new JavaParserTypeParameter(this.wrappedNode, typeSolver); + } + + /** + * Returns the JavaParser node associated with this JavaParserTypeVariableDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public TypeParameter getWrappedNode() { + return wrappedNode; + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + return asTypeParameter().containerType(); + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/AbstractSymbolDeclarator.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/AbstractSymbolDeclarator.java new file mode 100644 index 000000000..14fdafcd0 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/AbstractSymbolDeclarator.java @@ -0,0 +1,35 @@ +/* + * 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.declarators; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; + +/** + * @author Federico Tomassetti + */ +public abstract class AbstractSymbolDeclarator<N extends Node> implements SymbolDeclarator { + + protected N wrappedNode; + protected TypeSolver typeSolver; + + public AbstractSymbolDeclarator(N wrappedNode, TypeSolver typeSolver) { + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/FieldSymbolDeclarator.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/FieldSymbolDeclarator.java new file mode 100644 index 000000000..dddf7a538 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/FieldSymbolDeclarator.java @@ -0,0 +1,46 @@ +/* + * 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.declarators; + +import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author Federico Tomassetti + */ +public class FieldSymbolDeclarator extends AbstractSymbolDeclarator<FieldDeclaration> { + + public FieldSymbolDeclarator(FieldDeclaration wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public List<ResolvedValueDeclaration> getSymbolDeclarations() { + List<ResolvedValueDeclaration> symbols = new LinkedList<>(); + for (VariableDeclarator v : wrappedNode.getVariables()) { + symbols.add(JavaParserSymbolDeclaration.field(v, typeSolver)); + } + return symbols; + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/NoSymbolDeclarator.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/NoSymbolDeclarator.java new file mode 100644 index 000000000..e950b70ee --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/NoSymbolDeclarator.java @@ -0,0 +1,40 @@ +/* + * 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.declarators; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.Collections; +import java.util.List; + +/** + * @author Federico Tomassetti + */ +public class NoSymbolDeclarator<N extends Node> extends AbstractSymbolDeclarator<N> { + + public NoSymbolDeclarator(N wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public List<ResolvedValueDeclaration> getSymbolDeclarations() { + return Collections.emptyList(); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/ParameterSymbolDeclarator.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/ParameterSymbolDeclarator.java new file mode 100644 index 000000000..45d8e160f --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/ParameterSymbolDeclarator.java @@ -0,0 +1,42 @@ +/* + * 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.declarators; + +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author Federico Tomassetti + */ +public class ParameterSymbolDeclarator extends AbstractSymbolDeclarator<Parameter> { + + public ParameterSymbolDeclarator(Parameter wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + } + + @Override + public List<ResolvedValueDeclaration> getSymbolDeclarations() { + List<ResolvedValueDeclaration> symbols = new LinkedList<>(); + symbols.add(JavaParserSymbolDeclaration.parameter(wrappedNode, typeSolver)); + return symbols; + } +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/VariableSymbolDeclarator.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/VariableSymbolDeclarator.java new file mode 100644 index 000000000..88865de0d --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarators/VariableSymbolDeclarator.java @@ -0,0 +1,52 @@ +/* + * 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.declarators; + +import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; + +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode; + +/** + * @author Federico Tomassetti + */ +public class VariableSymbolDeclarator extends AbstractSymbolDeclarator<VariableDeclarationExpr> { + + public VariableSymbolDeclarator(VariableDeclarationExpr wrappedNode, TypeSolver typeSolver) { + super(wrappedNode, typeSolver); + wrappedNode.getParentNode().ifPresent(p -> { + if (p instanceof FieldDeclaration) { + throw new IllegalArgumentException(); + } + }); + } + + @Override + public List<ResolvedValueDeclaration> getSymbolDeclarations() { + return wrappedNode.getVariables().stream() + .map(v -> JavaParserSymbolDeclaration.localVar(v, typeSolver)) + .collect(Collectors.toCollection(LinkedList::new)); + } + +} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/package-info.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/package-info.java new file mode 100644 index 000000000..9ddf1cf01 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * Implementation of model based on JavaParser. + */ +package com.github.javaparser.symbolsolver.javaparsermodel;
\ No newline at end of file |