src: added test for indexing JavaSymbolSolver 0.6.0

* made DumpParserClient reusable by java tests
This commit is contained in:
mlangkabel
2017-09-28 17:50:17 +02:00
parent 83c24c5cd0
commit 0c437fbab0
279 changed files with 62442 additions and 161 deletions
@@ -0,0 +1,216 @@
/*
* 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;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* It prints information extracted from a source file. It is mainly intended as an example usage of JavaSymbolSolver.
*
* @author Federico Tomassetti
*/
public class SourceFileInfoExtractor {
private TypeSolver typeSolver;
private int ok = 0;
private int ko = 0;
private int unsupported = 0;
private boolean printFileName = true;
private PrintStream out = System.out;
private PrintStream err = System.err;
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
private boolean verbose = false;
public void setPrintFileName(boolean printFileName) {
this.printFileName = printFileName;
}
public void clear() {
ok = 0;
ko = 0;
unsupported = 0;
}
public void setOut(PrintStream out) {
this.out = out;
}
public void setErr(PrintStream err) {
this.err = err;
}
public int getOk() {
return ok;
}
public int getUnsupported() {
return unsupported;
}
public int getKo() {
return ko;
}
private void solveTypeDecl(ClassOrInterfaceDeclaration node) {
TypeDeclaration typeDeclaration = JavaParserFacade.get(typeSolver).getTypeDeclaration(node);
if (typeDeclaration.isClass()) {
out.println("\n[ Class " + typeDeclaration.getQualifiedName() + " ]");
for (ReferenceType sc : typeDeclaration.asClass().getAllSuperClasses()) {
out.println(" superclass: " + sc.getQualifiedName());
}
for (ReferenceType sc : typeDeclaration.asClass().getAllInterfaces()) {
out.println(" interface: " + sc.getQualifiedName());
}
}
}
private void solve(Node node) {
if (node instanceof ClassOrInterfaceDeclaration) {
solveTypeDecl((ClassOrInterfaceDeclaration) node);
} else if (node instanceof Expression) {
if ((getParentNode(node) instanceof ImportDeclaration) || (getParentNode(node) instanceof Expression)
|| (getParentNode(node) instanceof MethodDeclaration)
|| (getParentNode(node) instanceof PackageDeclaration)) {
// skip
} else if ((getParentNode(node) instanceof Statement) || (getParentNode(node) instanceof VariableDeclarator)) {
try {
Type ref = JavaParserFacade.get(typeSolver).getType(node);
out.println(" Line " + node.getRange().get().begin.line + ") " + node + " ==> " + ref.describe());
ok++;
} catch (UnsupportedOperationException upe) {
unsupported++;
err.println(upe.getMessage());
throw upe;
} catch (RuntimeException re) {
ko++;
err.println(re.getMessage());
throw re;
}
}
}
}
private void solveMethodCalls(Node node) {
if (node instanceof MethodCallExpr) {
out.println(" Line " + node.getBegin().get().line + ") " + node + " ==> " + toString((MethodCallExpr) node));
}
for (Node child : node.getChildNodes()) {
solveMethodCalls(child);
}
}
private String toString(MethodCallExpr node) {
try {
return toString(JavaParserFacade.get(typeSolver).solve(node));
} catch (Exception e) {
if (verbose) {
System.err.println("Error resolving call at L" + node.getBegin().get().line + ": " + node);
e.printStackTrace();
}
return "ERROR";
}
}
private String toString(SymbolReference<com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration> methodDeclarationSymbolReference) {
if (methodDeclarationSymbolReference.isSolved()) {
return methodDeclarationSymbolReference.getCorrespondingDeclaration().getQualifiedSignature();
} else {
return "UNSOLVED";
}
}
private List<Node> collectAllNodes(Node node) {
List<Node> nodes = new LinkedList<>();
collectAllNodes(node, nodes);
nodes.sort((n1, n2) -> n1.getBegin().get().compareTo(n2.getBegin().get()));
return nodes;
}
private void collectAllNodes(Node node, List<Node> nodes) {
nodes.add(node);
node.getChildNodes().forEach(c -> collectAllNodes(c, nodes));
}
public void solve(File file) throws IOException, ParseException {
if (file.isDirectory()) {
for (File f : file.listFiles()) {
solve(f);
}
} else {
if (file.getName().endsWith(".java")) {
if (printFileName) {
out.println("- parsing " + file.getAbsolutePath());
}
CompilationUnit cu = JavaParser.parse(file);
List<Node> nodes = collectAllNodes(cu);
nodes.forEach(n -> solve(n));
}
}
}
public void solveMethodCalls(File file) throws IOException, ParseException {
if (file.isDirectory()) {
for (File f : file.listFiles()) {
solveMethodCalls(f);
}
} else {
if (file.getName().endsWith(".java")) {
if (printFileName) {
out.println("- parsing " + file.getAbsolutePath());
}
CompilationUnit cu = JavaParser.parse(file);
solveMethodCalls(cu);
}
}
}
public void setTypeSolver(TypeSolver typeSolver) {
this.typeSolver = typeSolver;
}
}
@@ -0,0 +1,98 @@
/*
* 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.core.resolution;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
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.Type;
import java.util.List;
import java.util.Optional;
/**
* Context is very similar to scope.
* In the context we look for solving symbols.
*
* @author Federico Tomassetti
*/
public interface Context {
Context getParent();
/* Type resolution */
default Optional<Type> solveGenericType(String name, TypeSolver typeSolver) {
return Optional.empty();
}
default SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
Context parent = getParent();
if (parent == null) {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
} else {
return parent.solveType(name, typeSolver);
}
}
/* Symbol resolution */
SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver);
default Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) {
SymbolReference<? extends ValueDeclaration> ref = solveSymbol(name, typeSolver);
if (ref.isSolved()) {
Value value = Value.from(ref.getCorrespondingDeclaration());
return Optional.of(value);
} else {
return Optional.empty();
}
}
/* Constructor resolution */
/**
* We find the method declaration which is the best match for the given name and list of typeParametersValues.
*/
default SymbolReference<ConstructorDeclaration> solveConstructor(List<Type> argumentsTypes, TypeSolver typeSolver) {
throw new IllegalArgumentException("Constructor resolution is available only on Class Context");
}
/* Methods resolution */
/**
* We find the method declaration which is the best match for the given name and list of typeParametersValues.
*/
SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver);
/**
* Similar to solveMethod but we return a MethodUsage. A MethodUsage corresponds to a MethodDeclaration plus the
* resolved type variables.
*/
default Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argumentsTypes, TypeSolver typeSolver) {
SymbolReference<MethodDeclaration> methodSolved = solveMethod(name, argumentsTypes, false, typeSolver);
if (methodSolved.isSolved()) {
MethodDeclaration methodDeclaration = methodSolved.getCorrespondingDeclaration();
MethodUsage methodUsage = ContextHelper.resolveTypeVariables(this, methodDeclaration, argumentsTypes);//methodDeclaration.resolveTypeVariables(this, argumentsTypes);
return Optional.of(methodUsage);
} else {
return Optional.empty();
}
}
}
@@ -0,0 +1,51 @@
/*
* 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.core.resolution;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration;
import com.github.javaparser.symbolsolver.javassistmodel.JavassistMethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionMethodDeclaration;
import java.util.List;
/**
* @author Federico Tomassetti
*/
class ContextHelper {
private ContextHelper() {
// prevent instantiation
}
static MethodUsage resolveTypeVariables(Context context, MethodDeclaration methodDeclaration, List<Type> parameterTypes) {
if (methodDeclaration instanceof JavaParserMethodDeclaration) {
return ((JavaParserMethodDeclaration) methodDeclaration).resolveTypeVariables(context, parameterTypes);
} else if (methodDeclaration instanceof JavassistMethodDeclaration) {
return ((JavassistMethodDeclaration) methodDeclaration).resolveTypeVariables(context, parameterTypes);
} else if (methodDeclaration instanceof JavaParserEnumDeclaration.ValuesMethod) {
return ((JavaParserEnumDeclaration.ValuesMethod) methodDeclaration).resolveTypeVariables(context, parameterTypes);
} else if (methodDeclaration instanceof ReflectionMethodDeclaration) {
return ((ReflectionMethodDeclaration) methodDeclaration).resolveTypeVariables(context, parameterTypes);
} else {
throw new UnsupportedOperationException();
}
}
}
@@ -0,0 +1,94 @@
/*
* 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.declarations.common;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.logic.InferenceContext;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
import com.github.javaparser.symbolsolver.reflectionmodel.MyObjectProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author Federico Tomassetti
*/
public class MethodDeclarationCommonLogic {
private MethodDeclaration methodDeclaration;
private TypeSolver typeSolver;
public MethodDeclarationCommonLogic(MethodDeclaration methodDeclaration, TypeSolver typeSolver) {
this.methodDeclaration = methodDeclaration;
this.typeSolver = typeSolver;
}
public MethodUsage resolveTypeVariables(Context context, List<Type> parameterTypes) {
Type returnType = replaceTypeParams(methodDeclaration.getReturnType(), typeSolver, context);
List<Type> params = new ArrayList<>();
for (int i = 0; i < methodDeclaration.getNumberOfParams(); i++) {
Type replaced = replaceTypeParams(methodDeclaration.getParam(i).getType(), typeSolver, context);
params.add(replaced);
}
// We now look at the type parameter for the method which we can derive from the parameter types
// and then we replace them in the return type
// Map<TypeParameterDeclaration, Type> determinedTypeParameters = new HashMap<>();
InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE);
for (int i = 0; i < methodDeclaration.getNumberOfParams() - (methodDeclaration.hasVariadicParameter() ? 1 : 0); i++) {
Type formalParamType = methodDeclaration.getParam(i).getType();
Type actualParamType = parameterTypes.get(i);
inferenceContext.addPair(formalParamType, actualParamType);
}
returnType = inferenceContext.resolve(inferenceContext.addSingle(returnType));
return new MethodUsage(methodDeclaration, params, returnType);
}
private Type replaceTypeParams(Type type, TypeSolver typeSolver, Context context) {
if (type.isTypeVariable()) {
TypeParameterDeclaration typeParameter = type.asTypeParameter();
if (typeParameter.declaredOnType()) {
Optional<Type> typeParam = typeParamByName(typeParameter.getName(), typeSolver, context);
if (typeParam.isPresent()) {
type = typeParam.get();
}
}
}
if (type.isReferenceType()) {
type.asReferenceType().transformTypeParameters(tp -> replaceTypeParams(tp, typeSolver, context));
}
return type;
}
protected Optional<Type> typeParamByName(String name, TypeSolver typeSolver, Context context) {
return methodDeclaration.getTypeParameters().stream().filter(tp -> tp.getName().equals(name)).map(tp -> toType(tp)).findFirst();
}
protected Type toType(TypeParameterDeclaration typeParameterDeclaration) {
return new TypeVariable(typeParameterDeclaration);
}
}
@@ -0,0 +1,295 @@
/*
* 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.javaparser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.stmt.ReturnStmt;
import com.github.javaparser.ast.stmt.SwitchStmt;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
/**
* This class can be used to easily retrieve nodes from a JavaParser AST.
*
* @author Federico Tomassetti
*/
public final class Navigator {
private Navigator() {
// prevent instantiation
}
public static Node getParentNode(Node node) {
Node parent = node.getParentNode().orElse(null);
return parent;
}
public static Optional<TypeDeclaration<?>> findType(CompilationUnit cu, String qualifiedName) {
if (cu.getTypes().isEmpty()) {
return Optional.empty();
}
final String typeName = getOuterTypeName(qualifiedName);
Optional<TypeDeclaration<?>> type = cu.getTypes().stream().filter((t) -> t.getName().getId().equals(typeName)).findFirst();
final String innerTypeName = getInnerTypeName(qualifiedName);
if (type.isPresent() && !innerTypeName.isEmpty()) {
return findType(type.get(), innerTypeName);
}
return type;
}
public static Optional<TypeDeclaration<?>> findType(TypeDeclaration<?> td, String qualifiedName) {
final String typeName = getOuterTypeName(qualifiedName);
Optional<TypeDeclaration<?>> type = Optional.empty();
for (Node n : td.getMembers()) {
if (n instanceof TypeDeclaration && ((TypeDeclaration<?>) n).getName().getId().equals(typeName)) {
type = Optional.of((TypeDeclaration<?>) n);
break;
}
}
final String innerTypeName = getInnerTypeName(qualifiedName);
if (type.isPresent() && !innerTypeName.isEmpty()) {
return findType(type.get(), innerTypeName);
}
return type;
}
public static ClassOrInterfaceDeclaration demandClass(CompilationUnit cu, String qualifiedName) {
ClassOrInterfaceDeclaration cd = demandClassOrInterface(cu, qualifiedName);
if (cd.isInterface()) {
throw new IllegalStateException("Type is not a class");
}
return cd;
}
public static EnumDeclaration demandEnum(CompilationUnit cu, String qualifiedName) {
Optional<TypeDeclaration<?>> res = findType(cu, qualifiedName);
if (!res.isPresent()) {
throw new IllegalStateException("No type found");
}
if (!(res.get() instanceof EnumDeclaration)) {
throw new IllegalStateException("Type is not an enum");
}
return (EnumDeclaration) res.get();
}
public static MethodDeclaration demandMethod(TypeDeclaration<?> cd, String name) {
MethodDeclaration found = null;
for (BodyDeclaration<?> bd : cd.getMembers()) {
if (bd instanceof MethodDeclaration) {
MethodDeclaration md = (MethodDeclaration) bd;
if (md.getName().getId().equals(name)) {
if (found != null) {
throw new IllegalStateException("Ambiguous getName");
}
found = md;
}
}
}
if (found == null) {
throw new IllegalStateException("No method with given name");
}
return found;
}
public static VariableDeclarator demandField(ClassOrInterfaceDeclaration cd, String name) {
for (BodyDeclaration<?> bd : cd.getMembers()) {
if (bd instanceof FieldDeclaration) {
FieldDeclaration fd = (FieldDeclaration) bd;
for (VariableDeclarator vd : fd.getVariables()) {
if (vd.getName().getId().equals(name)) {
return vd;
}
}
}
}
throw new IllegalStateException("No field with given name");
}
public static NameExpr findNameExpression(Node node, String name) {
if (node instanceof NameExpr) {
NameExpr nameExpr = (NameExpr) node;
if (nameExpr.getName() != null && nameExpr.getName().getId().equals(name)) {
return nameExpr;
}
}
for (Node child : node.getChildNodes()) {
NameExpr res = findNameExpression(child, name);
if (res != null) {
return res;
}
}
return null;
}
public static SimpleName findSimpleName(Node node, String name) {
if (node instanceof SimpleName) {
SimpleName nameExpr = (SimpleName) node;
if (nameExpr.getId() != null && nameExpr.getId().equals(name)) {
return nameExpr;
}
}
for (Node child : node.getChildNodes()) {
SimpleName res = findSimpleName(child, name);
if (res != null) {
return res;
}
}
return null;
}
public static MethodCallExpr findMethodCall(Node node, String methodName) {
if (node instanceof MethodCallExpr) {
MethodCallExpr methodCallExpr = (MethodCallExpr) node;
if (methodCallExpr.getName().getId().equals(methodName)) {
return methodCallExpr;
}
}
for (Node child : node.getChildNodes()) {
MethodCallExpr res = findMethodCall(child, methodName);
if (res != null) {
return res;
}
}
return null;
}
public static VariableDeclarator demandVariableDeclaration(Node node, String name) {
if (node instanceof VariableDeclarator) {
VariableDeclarator variableDeclarator = (VariableDeclarator) node;
if (variableDeclarator.getName().getId().equals(name)) {
return variableDeclarator;
}
}
for (Node child : node.getChildNodes()) {
VariableDeclarator res = demandVariableDeclaration(child, name);
if (res != null) {
return res;
}
}
return null;
}
public static ClassOrInterfaceDeclaration demandClassOrInterface(CompilationUnit compilationUnit, String qualifiedName) {
Optional<TypeDeclaration<?>> res = findType(compilationUnit, qualifiedName);
if (!res.isPresent()) {
throw new IllegalStateException("No type named '" + qualifiedName + "'found");
}
if (!(res.get() instanceof ClassOrInterfaceDeclaration)) {
throw new IllegalStateException("Type is not a class or an interface, it is " + res.get().getClass().getCanonicalName());
}
ClassOrInterfaceDeclaration cd = (ClassOrInterfaceDeclaration) res.get();
return cd;
}
public static SwitchStmt findSwitch(Node node) {
SwitchStmt res = findSwitchHelper(node);
if (res == null) {
throw new IllegalArgumentException();
} else {
return res;
}
}
public static <N> N findNodeOfGivenClass(Node node, Class<N> clazz) {
N res = findNodeOfGivenClassHelper(node, clazz);
if (res == null) {
throw new IllegalArgumentException();
} else {
return res;
}
}
public static <N> List<N> findAllNodesOfGivenClass(Node node, Class<N> clazz) {
List<N> res = new LinkedList<>();
findAllNodesOfGivenClassHelper(node, clazz, res);
return res;
}
public static ReturnStmt findReturnStmt(MethodDeclaration method) {
return findNodeOfGivenClass(method, ReturnStmt.class);
}
public static <N extends Node> Optional<N> findAncestor(Node node, Class<N> clazz) {
if (!node.getParentNode().isPresent()) {
return Optional.empty();
} else if (clazz.isInstance(node.getParentNode().get())) {
return Optional.of(clazz.cast(node.getParentNode().get()));
} else {
return findAncestor(node.getParentNode().get(), clazz);
}
}
///
/// Private methods
///
private static String getOuterTypeName(String qualifiedName) {
return qualifiedName.split("\\.", 2)[0];
}
private static String getInnerTypeName(String qualifiedName) {
if (qualifiedName.contains(".")) {
return qualifiedName.split("\\.", 2)[1];
}
return "";
}
private static SwitchStmt findSwitchHelper(Node node) {
if (node instanceof SwitchStmt) {
return (SwitchStmt) node;
}
for (Node child : node.getChildNodes()) {
SwitchStmt resChild = findSwitchHelper(child);
if (resChild != null) {
return resChild;
}
}
return null;
}
private static <N> N findNodeOfGivenClassHelper(Node node, Class<N> clazz) {
if (clazz.isInstance(node)) {
return clazz.cast(node);
}
for (Node child : node.getChildNodes()) {
N resChild = findNodeOfGivenClassHelper(child, clazz);
if (resChild != null) {
return resChild;
}
}
return null;
}
private static <N> void findAllNodesOfGivenClassHelper(Node node, Class<N> clazz, List<N> collector) {
if (clazz.isInstance(node)) {
collector.add(clazz.cast(node));
}
for (Node child : node.getChildNodes()) {
findAllNodesOfGivenClassHelper(child, clazz, collector);
}
}
}
@@ -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.
*/
/**
* This package contains utility to use JavaParser.
*/
package com.github.javaparser.symbolsolver.javaparser;
@@ -0,0 +1,465 @@
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.symbolsolver.model.typesystem.Type;
public class DefaultVisitorAdapter implements GenericVisitor<Type, Boolean> {
@Override
public Type visit(CompilationUnit node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(PackageDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(TypeParameter node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(LineComment node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(BlockComment node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ClassOrInterfaceDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(EnumDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(EnumConstantDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(AnnotationDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(AnnotationMemberDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(FieldDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(VariableDeclarator node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ConstructorDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(MethodDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(Parameter node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(InitializerDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(JavadocComment node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ClassOrInterfaceType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(PrimitiveType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ArrayType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ArrayCreationLevel node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(IntersectionType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(UnionType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(VoidType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(WildcardType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(UnknownType node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ArrayAccessExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ArrayCreationExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ArrayInitializerExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(AssignExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(BinaryExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(CastExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ClassExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ConditionalExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(EnclosedExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(FieldAccessExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(InstanceOfExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(StringLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(IntegerLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(LongLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(CharLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(DoubleLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(BooleanLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(NullLiteralExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(MethodCallExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(NameExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ObjectCreationExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ThisExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(SuperExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(UnaryExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(VariableDeclarationExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(MarkerAnnotationExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(SingleMemberAnnotationExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(NormalAnnotationExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(MemberValuePair node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ExplicitConstructorInvocationStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(LocalClassDeclarationStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(AssertStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(BlockStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(LabeledStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(EmptyStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ExpressionStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(SwitchStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(SwitchEntryStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(BreakStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ReturnStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(IfStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(WhileStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ContinueStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(DoStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ForeachStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ForStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ThrowStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(SynchronizedStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(TryStmt node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(CatchClause node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(LambdaExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(MethodReferenceExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(TypeExpr node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(NodeList node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(Name node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(SimpleName node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ImportDeclaration node, Boolean aBoolean) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ModuleDeclaration node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ModuleRequiresStmt node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ModuleExportsStmt node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ModuleProvidesStmt node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ModuleUsesStmt node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(ModuleOpensStmt node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(UnparsableStmt node, Boolean arg) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
}
@@ -0,0 +1,531 @@
/*
* 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.ClassOrInterfaceType;
import com.github.javaparser.ast.type.UnknownType;
import com.github.javaparser.ast.type.WildcardType;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.declarations.AnnotationDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ConstructorDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
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.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.getParentNode;
/**
* 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, Type> cacheWithLambdasSolved = new IdentityHashMap<>();
private Map<Node, Type> 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 Type solveGenericTypes(Type type, Context context, TypeSolver typeSolver) {
if (type.isTypeVariable()) {
Optional<Type> solved = context.solveGenericType(type.describe(), typeSolver);
if (solved.isPresent()) {
return solved.get();
} else {
return type;
}
} else if (type.isWildcard()) {
if (type.asWildcard().isExtends() || type.asWildcard().isSuper()) {
Wildcard wildcardUsage = type.asWildcard();
Type boundResolved = solveGenericTypes(wildcardUsage.getBoundedType(), context, typeSolver);
if (wildcardUsage.isExtends()) {
return Wildcard.extendsBound(boundResolved);
} else {
return Wildcard.superBound(boundResolved);
}
} else {
return type;
}
} else {
Type result = type;
return result;
}
}
public SymbolReference<? extends ValueDeclaration> solve(NameExpr nameExpr) {
return symbolSolver.solveSymbol(nameExpr.getName().getId(), nameExpr);
}
public SymbolReference<? extends ValueDeclaration> solve(SimpleName nameExpr) {
return symbolSolver.solveSymbol(nameExpr.getId(), nameExpr);
}
public SymbolReference<? extends ValueDeclaration> solve(Expression expr) {
if (expr instanceof NameExpr) {
return solve((NameExpr) expr);
} else {
throw new IllegalArgumentException(expr.getClass().getCanonicalName());
}
}
public SymbolReference<MethodDeclaration> solve(MethodCallExpr methodCallExpr) {
return solve(methodCallExpr, true);
}
public SymbolReference<ConstructorDeclaration> solve(ObjectCreationExpr objectCreationExpr) {
return solve(objectCreationExpr, true);
}
public SymbolReference<ConstructorDeclaration> solve(ExplicitConstructorInvocationStmt explicitConstructorInvocationStmt) {
return solve(explicitConstructorInvocationStmt, true);
}
public SymbolReference<ConstructorDeclaration> solve(ExplicitConstructorInvocationStmt explicitConstructorInvocationStmt, boolean solveLambdas) {
List<Type> 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(ConstructorDeclaration.class);
}
ClassOrInterfaceDeclaration classNode = optAncestor.get();
TypeDeclaration typeDecl = null;
if (!explicitConstructorInvocationStmt.isThis()) {
Type classDecl = JavaParserFacade.get(typeSolver).convert(classNode.getExtendedTypes(0), classNode);
if (classDecl.isReferenceType()) {
typeDecl = classDecl.asReferenceType().getTypeDeclaration();
}
} else {
SymbolReference<TypeDeclaration> sr = JavaParserFactory.getContext(classNode, typeSolver).solveType(classNode.getNameAsString(), typeSolver);
if (sr.isSolved()) {
typeDecl = sr.getCorrespondingDeclaration();
}
}
if (typeDecl == null) {
return SymbolReference.unsolved(ConstructorDeclaration.class);
}
SymbolReference<ConstructorDeclaration> res = ConstructorResolutionLogic.findMostApplicable(((ClassDeclaration) typeDecl).getConstructors(), argumentTypes, typeSolver);
for (LambdaArgumentTypePlaceholder placeholder : placeholders) {
placeholder.setMethod(res);
}
return res;
}
public SymbolReference<TypeDeclaration> 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<ReferenceTypeDeclaration> 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(findContainingTypeDecl(node)));
}
/**
* Given a constructor call find out to which constructor declaration it corresponds.
*/
public SymbolReference<ConstructorDeclaration> solve(ObjectCreationExpr objectCreationExpr, boolean solveLambdas) {
List<Type> argumentTypes = new LinkedList<>();
List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>();
solveArguments(objectCreationExpr, objectCreationExpr.getArguments(), solveLambdas, argumentTypes, placeholders);
Type classDecl = JavaParserFacade.get(typeSolver).convert(objectCreationExpr.getType(), objectCreationExpr);
if (!classDecl.isReferenceType()) {
return SymbolReference.unsolved(ConstructorDeclaration.class);
}
SymbolReference<ConstructorDeclaration> res = ConstructorResolutionLogic.findMostApplicable(((ClassDeclaration) 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<Type> 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 (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<MethodDeclaration> solve(MethodCallExpr methodCallExpr, boolean solveLambdas) {
List<Type> argumentTypes = new LinkedList<>();
List<LambdaArgumentTypePlaceholder> placeholders = new LinkedList<>();
solveArguments(methodCallExpr, methodCallExpr.getArguments(), solveLambdas, argumentTypes, placeholders);
SymbolReference<MethodDeclaration> res = JavaParserFactory.getContext(methodCallExpr, typeSolver).solveMethod(methodCallExpr.getName().getId(), argumentTypes, false, typeSolver);
for (LambdaArgumentTypePlaceholder placeholder : placeholders) {
placeholder.setMethod(res);
}
return res;
}
public SymbolReference<AnnotationDeclaration> solve(AnnotationExpr annotationExpr) {
Context context = JavaParserFactory.getContext(annotationExpr, typeSolver);
SymbolReference<TypeDeclaration> typeDeclarationSymbolReference = context.solveType(annotationExpr.getNameAsString(), typeSolver);
AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration) typeDeclarationSymbolReference.getCorrespondingDeclaration();
if (typeDeclarationSymbolReference.isSolved()) {
return SymbolReference.solved(annotationDeclaration);
} else {
return SymbolReference.unsolved(AnnotationDeclaration.class);
}
}
public Type getType(Node node) {
return getType(node, true);
}
public Type getType(Node node, boolean solveLambdas) {
if (solveLambdas) {
if (!cacheWithLambdasSolved.containsKey(node)) {
Type res = getTypeConcrete(node, solveLambdas);
cacheWithLambdasSolved.put(node, res);
boolean secondPassNecessary = false;
if (node instanceof MethodCallExpr) {
MethodCallExpr methodCallExpr = (MethodCallExpr) node;
for (Node arg : methodCallExpr.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<Type> res = find(cacheWithLambdasSolved, node);
if (res.isPresent()) {
return res.get();
}
res = find(cacheWithoutLambdasSolved, node);
if (!res.isPresent()) {
Type resType = getTypeConcrete(node, solveLambdas);
cacheWithoutLambdasSolved.put(node, resType);
logger.finer("getType on " + node + " (no solveLambdas) -> " + res);
return resType;
}
return res.get();
}
}
private Optional<Type> find(Map<Node, Type> map, Node node) {
if (map.containsKey(node)) {
return Optional.of(map.get(node));
}
if (node instanceof LambdaExpr) {
return find(map, (LambdaExpr) node);
} else {
return Optional.empty();
}
}
/**
* For some reasons LambdaExprs are duplicate and the equals method is not implemented correctly.
*
* @param map
* @return
*/
private Optional<Type> find(Map<Node, Type> map, LambdaExpr lambdaExpr) {
for (Node key : map.keySet()) {
if (key instanceof LambdaExpr) {
LambdaExpr keyLambdaExpr = (LambdaExpr) key;
if (keyLambdaExpr.toString().equals(lambdaExpr.toString()) && getParentNode(keyLambdaExpr) == getParentNode(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<TypeDeclaration> typeDeclarationSymbolReference = JavaParserFactory.getContext(classOrInterfaceType, typeSolver).solveType(classOrInterfaceType.getName().getId(), typeSolver);
if (!typeDeclarationSymbolReference.isSolved()) {
throw new UnsupportedOperationException();
}
List<MethodUsage> methodUsages = ((ReferenceTypeDeclaration) 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 Type getBinaryTypeConcrete(Node left, Node right, boolean solveLambdas) {
Type leftType = getTypeConcrete(left, solveLambdas);
Type 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.
*
* @return
*/
private Type 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;
} else if (node instanceof EnumDeclaration) {
return (EnumDeclaration) node;
} else if (getParentNode(node) == null) {
throw new IllegalArgumentException();
} else {
return findContainingTypeDecl(getParentNode(node));
}
}
public Type convertToUsageVariableType(VariableDeclarator var) {
Type type = JavaParserFacade.get(typeSolver).convertToUsage(var.getType(), var);
return type;
}
public Type convertToUsage(com.github.javaparser.ast.type.Type type, Node context) {
if (type instanceof UnknownType) {
throw new IllegalArgumentException("Unknown type");
}
return convertToUsage(type, JavaParserFactory.getContext(context, typeSolver));
}
public Type 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;
} else {
return name;
}
}
protected Type convertToUsage(com.github.javaparser.ast.type.Type type, Context context) {
if (type instanceof ClassOrInterfaceType) {
ClassOrInterfaceType classOrInterfaceType = (ClassOrInterfaceType) type;
String name = qName(classOrInterfaceType);
SymbolReference<TypeDeclaration> ref = context.solveType(name, typeSolver);
if (!ref.isSolved()) {
throw new UnsolvedSymbolException(name);
}
TypeDeclaration typeDeclaration = ref.getCorrespondingDeclaration();
List<Type> 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 TypeParameterDeclaration) {
return new TypeVariable((TypeParameterDeclaration) typeDeclaration);
} else {
JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) typeDeclaration;
return new TypeVariable(javaParserTypeVariableDeclaration.asTypeParameter());
}
} else {
return new ReferenceTypeImpl((ReferenceTypeDeclaration) typeDeclaration, typeParameters, typeSolver);
}
} else if (type instanceof com.github.javaparser.ast.type.PrimitiveType) {
return PrimitiveType.byName(((com.github.javaparser.ast.type.PrimitiveType) type).getType().name());
} else if (type instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) type;
if (wildcardType.getExtendedTypes().isPresent() && !wildcardType.getSuperTypes().isPresent()) {
return Wildcard.extendsBound(convertToUsage(wildcardType.getExtendedTypes().get(), context)); // removed (ReferenceTypeImpl)
} else if (!wildcardType.getExtendedTypes().isPresent() && wildcardType.getSuperTypes().isPresent()) {
return Wildcard.superBound(convertToUsage(wildcardType.getSuperTypes().get(), context)); // removed (ReferenceTypeImpl)
} else if (!wildcardType.getExtendedTypes().isPresent() && !wildcardType.getSuperTypes().isPresent()) {
return Wildcard.UNBOUNDED;
} else {
throw new UnsupportedOperationException(wildcardType.toString());
}
} else if (type instanceof com.github.javaparser.ast.type.VoidType) {
return VoidType.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 ArrayType(convertToUsage(jpArrayType.getComponentType(), context));
} else {
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
}
public Type convert(com.github.javaparser.ast.type.Type type, Node node) {
return convert(type, JavaParserFactory.getContext(node, typeSolver));
}
public Type convert(com.github.javaparser.ast.type.Type type, Context context) {
return convertToUsage(type, context);
}
public MethodUsage solveMethodAsUsage(MethodCallExpr call) {
List<Type> 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().get().begin.line + ") " + context + ". Parameter types: " + params);
}
return methodUsage.get();
}
public ReferenceTypeDeclaration getTypeDeclaration(ClassOrInterfaceDeclaration classOrInterfaceDeclaration) {
return JavaParserFactory.toTypeDeclaration(classOrInterfaceDeclaration, typeSolver);
}
/**
* "this" inserted in the given point, which type would have?
*/
public Type getTypeOfThisIn(Node node) {
// TODO consider static methods
if (node instanceof ClassOrInterfaceDeclaration) {
return new ReferenceTypeImpl(getTypeDeclaration((ClassOrInterfaceDeclaration) node), typeSolver);
} else if (node instanceof EnumDeclaration) {
JavaParserEnumDeclaration enumDeclaration = new JavaParserEnumDeclaration((EnumDeclaration) node, typeSolver);
return new ReferenceTypeImpl(enumDeclaration, typeSolver);
} else {
return getTypeOfThisIn(getParentNode(node));
}
}
public ReferenceTypeDeclaration getTypeDeclaration(com.github.javaparser.ast.body.TypeDeclaration<?> typeDeclaration) {
return JavaParserFactory.toTypeDeclaration(typeDeclaration, typeSolver);
}
}
@@ -0,0 +1,135 @@
/*
* 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.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.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserFactory {
public static Context getContext(Node node, TypeSolver typeSolver) {
if (node == null) {
return 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>((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 = getParentNode(node);
if(parentNode instanceof ObjectCreationExpr && node == ((ObjectCreationExpr) parentNode).getType()) {
return getContext(getParentNode(parentNode), typeSolver);
}
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>(expressionStmt, typeSolver);
}
} else if (node instanceof IfStmt) {
return new NoSymbolDeclarator<IfStmt>((IfStmt) node, typeSolver);
} else if (node instanceof ForeachStmt) {
ForeachStmt foreachStmt = (ForeachStmt) node;
return new VariableSymbolDeclarator((VariableDeclarationExpr) (foreachStmt.getVariable()), typeSolver);
} else {
return new NoSymbolDeclarator<Node>(node, typeSolver);
}
}
public static ReferenceTypeDeclaration 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());
}
}
}
@@ -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.symbolsolver.model.declarations.MethodLikeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
/**
* Placeholder used to represent a lambda argument type while it is being
* calculated.
*
* @author Federico Tomassetti
*/
public class LambdaArgumentTypePlaceholder implements Type {
private int pos;
private SymbolReference<? extends MethodLikeDeclaration> 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 MethodLikeDeclaration> method) {
this.method = method;
}
@Override
public boolean isAssignableBy(Type other) {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,523 @@
package com.github.javaparser.symbolsolver.javaparsermodel;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
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.stmt.Statement;
import com.github.javaparser.ast.type.UnknownType;
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.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
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.getParentNode;
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 Type visit(VariableDeclarator node, Boolean solveLambdas) {
if (getParentNode(node) instanceof FieldDeclaration) {
// FieldDeclaration parent = (FieldDeclaration) getParentNode(node);
return facade.convertToUsageVariableType(node);
} else if (getParentNode(node) instanceof VariableDeclarationExpr) {
// VariableDeclarationExpr parent = (VariableDeclarationExpr) getParentNode(node);
return facade.convertToUsageVariableType(node);
} else {
throw new UnsupportedOperationException(getParentNode(node).getClass().getCanonicalName());
}
}
@Override
public Type 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 Type visit(ArrayAccessExpr node, Boolean solveLambdas) {
Type arrayUsageType = node.getName().accept(this, solveLambdas);
if (arrayUsageType.isArray()) {
return ((ArrayType) arrayUsageType).getComponentType();
}
return arrayUsageType;
}
@Override
public Type visit(ArrayCreationExpr node, Boolean solveLambdas) {
Type res = facade.convertToUsage(node.getElementType(), JavaParserFactory.getContext(node, typeSolver));
for (int i = 0; i < node.getLevels().size(); i++) {
res = new ArrayType(res);
}
return res;
}
@Override
public Type visit(ArrayInitializerExpr node, Boolean solveLambdas) {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
@Override
public Type visit(AssignExpr node, Boolean solveLambdas) {
return node.getTarget().accept(this, solveLambdas);
}
@Override
public Type 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 PrimitiveType.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("FOO " + node.getOperator().name());
}
}
@Override
public Type visit(CastExpr node, Boolean solveLambdas) {
return facade.convertToUsage(node.getType(), JavaParserFactory.getContext(node, typeSolver));
}
@Override
public Type 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();
Type jssType = facade.convertToUsage(astType, node.getType());
return new ReferenceTypeImpl(new ReflectionClassDeclaration(Class.class, typeSolver), ImmutableList.of(jssType), typeSolver);
}
@Override
public Type visit(ConditionalExpr node, Boolean solveLambdas) {
return node.getThenExpr().accept(this, solveLambdas);
}
@Override
public Type 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 Type solveDotExpressionType(ReferenceTypeDeclaration 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 Type 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<TypeDeclaration> 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<TypeDeclaration> solve = facade.solve((ThisExpr) node.getScope());
// If found get it's declaration and get the field in there
if (solve.isSolved()){
TypeDeclaration correspondingDeclaration = solve.getCorrespondingDeclaration();
if (correspondingDeclaration instanceof ReferenceTypeDeclaration){
return solveDotExpressionType(correspondingDeclaration.asReferenceType(), node);
}
}
} else if (node.getScope().toString().indexOf('.') > 0) {
// try to find fully qualified name
SymbolReference<ReferenceTypeDeclaration> sr = typeSolver.tryToSolveType(node.getScope().toString());
if (sr.isSolved()) {
return solveDotExpressionType(sr.getCorrespondingDeclaration(), node);
}
}
Optional<Value> value = null;
try {
value = new SymbolSolver(typeSolver).solveSymbolAsValue(node.getField().getId(), node);
} catch (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<ReferenceTypeDeclaration> sref = typeSolver.tryToSolveType(node.toString());
if (sref.isSolved()) {
return new ReferenceTypeImpl(sref.getCorrespondingDeclaration(), typeSolver);
}
}
if (value != null && value.isPresent()) {
return value.get().getType();
} else {
throw new UnsolvedSymbolException(node.getField().getId());
}
}
@Override
public Type visit(InstanceOfExpr node, Boolean solveLambdas) {
return PrimitiveType.BOOLEAN;
}
@Override
public Type visit(StringLiteralExpr node, Boolean solveLambdas) {
return new ReferenceTypeImpl(new ReflectionTypeSolver().solveType("java.lang.String"), typeSolver);
}
@Override
public Type visit(IntegerLiteralExpr node, Boolean solveLambdas) {
return PrimitiveType.INT;
}
@Override
public Type visit(LongLiteralExpr node, Boolean solveLambdas) {
return PrimitiveType.LONG;
}
@Override
public Type visit(CharLiteralExpr node, Boolean solveLambdas) {
return PrimitiveType.CHAR;
}
@Override
public Type visit(DoubleLiteralExpr node, Boolean solveLambdas) {
if (node.getValue().toLowerCase().endsWith("f")) {
return PrimitiveType.FLOAT;
}
return PrimitiveType.DOUBLE;
}
@Override
public Type visit(BooleanLiteralExpr node, Boolean solveLambdas) {
return PrimitiveType.BOOLEAN;
}
@Override
public Type visit(NullLiteralExpr node, Boolean solveLambdas) {
return NullType.INSTANCE;
}
@Override
public Type 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 Type 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 UnsolvedSymbolException("Solving " + node, node.getName().getId());
} else {
return value.get().getType();
}
}
@Override
public Type visit(ObjectCreationExpr node, Boolean solveLambdas) {
Type type = facade.convertToUsage(node.getType(), node);
return type;
}
@Override
public Type 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<ReferenceTypeDeclaration> 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.findContainingTypeDecl(node)), typeSolver);
}
@Override
public Type visit(SuperExpr node, Boolean solveLambdas) {
TypeDeclaration typeOfNode = facade.getTypeDeclaration(facade.findContainingTypeDecl(node));
if (typeOfNode instanceof ClassDeclaration) {
return ((ClassDeclaration) typeOfNode).getSuperClass();
} else {
throw new UnsupportedOperationException(node.getClass().getCanonicalName());
}
}
@Override
public Type visit(UnaryExpr node, Boolean solveLambdas) {
switch (node.getOperator()) {
case MINUS:
case PLUS:
return node.getExpression().accept(this, solveLambdas);
case LOGICAL_COMPLEMENT:
return PrimitiveType.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 Type visit(VariableDeclarationExpr node, Boolean solveLambdas) {
if (node.getVariables().size() != 1) {
throw new UnsupportedOperationException();
}
return facade.convertToUsageVariableType(node.getVariables().get(0));
}
@Override
public Type visit(LambdaExpr node, Boolean solveLambdas) {
if (getParentNode(node) instanceof MethodCallExpr) {
MethodCallExpr callExpr = (MethodCallExpr) getParentNode(node);
int pos = JavaParserSymbolDeclaration.getParamPos(node);
SymbolReference<MethodDeclaration> refMethod = facade.solve(callExpr);
if (!refMethod.isSolved()) {
throw new UnsolvedSymbolException(getParentNode(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
Type 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<TypeDeclaration> type = JavaParserFactory.getContext(nameExpr, typeSolver).solveType(nameExpr.getName().getId(), typeSolver);
if (type.isSolved()){
staticCall = true;
}
} catch (Exception e) {
}
}
if (!staticCall) {
Type 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 = facade.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
Type functionalInterfaceType = ReferenceTypeImpl.undeterminedParameters(functionalMethod.get().getDeclaration().declaringType(), typeSolver);
lambdaCtx.addPair(result, functionalInterfaceType);
Type actualType;
if (lambdaExpr.getBody() instanceof ExpressionStmt) {
actualType = facade.getType(((ExpressionStmt)lambdaExpr.getBody()).getExpression());
} else if (lambdaExpr.getBody() instanceof BlockStmt) {
BlockStmt blockStmt = (BlockStmt) lambdaExpr.getBody();
NodeList<Statement> statements = blockStmt.getStatements();
// Get all the return statements in the lambda block
List<ReturnStmt> returnStmts = blockStmt.getNodesByType(ReturnStmt.class);
if (returnStmts.size() > 0){
actualType = returnStmts.stream()
.map(returnStmt -> {
Optional<Expression> expression = returnStmt.getExpression();
if (expression.isPresent()){
return facade.getType(expression.get());
} else{
return VoidType.INSTANCE;
}
})
.filter(x -> x != null && !x.isVoid() && !x.isNull())
.findFirst()
.orElse(VoidType.INSTANCE);
} else {
return VoidType.INSTANCE;
}
} else {
throw new UnsupportedOperationException();
}
Type formalType = functionalMethod.get().returnType();
// Infer the functional interfaces' return vs actual type
funcInterfaceCtx.addPair(formalType, actualType);
// Substitute to obtain a new type
Type functionalTypeWithReturn = funcInterfaceCtx.resolve(funcInterfaceCtx.addSingle(functionalInterfaceType));
// if the functional method returns void anyway
// we don't need to bother inferring types
if (!(formalType instanceof VoidType)){
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 Type visit(MethodReferenceExpr node, Boolean solveLambdas) {
if (getParentNode(node) instanceof MethodCallExpr) {
MethodCallExpr callExpr = (MethodCallExpr) getParentNode(node);
int pos = JavaParserSymbolDeclaration.getParamPos(node);
SymbolReference<com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration> refMethod = facade.solve(callExpr, false);
if (!refMethod.isSolved()) {
throw new UnsolvedSymbolException(getParentNode(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);
Type result = usage.getParamType(pos);
// We need to replace the type variables
Context ctx = JavaParserFactory.getContext(node, typeSolver);
result = facade.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()) {
if (node instanceof MethodReferenceExpr) {
MethodReferenceExpr methodReferenceExpr = (MethodReferenceExpr) node;
Type actualType = facade.toMethodUsage(methodReferenceExpr).returnType();
Type formalType = functionalMethod.get().returnType();
InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE);
inferenceContext.addPair(formalType, actualType);
result = inferenceContext.resolve(inferenceContext.addSingle(result));
}
}
return result;
} else {
return refMethod.getCorrespondingDeclaration().getParam(pos).getType();
}
} else {
throw new UnsupportedOperationException("The type of a method reference expr depends on the position and its return value");
}
}
}
@@ -0,0 +1,67 @@
/*
* 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.symbolsolver.model.resolution.UnsolvedSymbolException} instead
*/
// Use the one in model instead
@Deprecated
public class UnsolvedSymbolException extends RuntimeException {
private String context;
private String name;
private TypeSolver typeSolver;
public UnsolvedSymbolException(String name, TypeSolver typeSolver) {
super("Unsolved symbol : " + name + " using typesolver " + typeSolver);
this.typeSolver = typeSolver;
this.name = name;
}
public UnsolvedSymbolException(Context context, String name) {
super("Unsolved symbol in " + context + " : " + name);
this.context = context.toString();
this.name = name;
}
public UnsolvedSymbolException(String context, String name) {
super("Unsolved symbol in " + context + " : " + name);
this.context = context;
this.name = name;
}
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 +
'}';
}
}
@@ -0,0 +1,138 @@
/*
* 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.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import java.util.Optional;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public abstract class AbstractJavaParserContext<N extends Node> implements Context {
protected N wrappedNode;
protected TypeSolver typeSolver;
///
/// Static methods
///
public static final SymbolReference<ValueDeclaration> solveWith(SymbolDeclarator symbolDeclarator, String name) {
for (ValueDeclaration decl : symbolDeclarator.getSymbolDeclarations()) {
if (decl.getName().equals(name)) {
return SymbolReference.solved(decl);
}
}
return SymbolReference.unsolved(ValueDeclaration.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<Type> 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() {
if (getParentNode(wrappedNode) instanceof MethodCallExpr) {
MethodCallExpr parentCall = (MethodCallExpr) getParentNode(wrappedNode);
boolean found = false;
if (parentCall.getArguments() != null) {
for (Expression expression : parentCall.getArguments()) {
if (expression == wrappedNode) {
found = true;
}
}
}
if (found) {
Node notMethod = getParentNode(wrappedNode);
while (notMethod instanceof MethodCallExpr) {
notMethod = getParentNode(notMethod);
}
return JavaParserFactory.getContext(notMethod, typeSolver);
}
}
Node notMethod = getParentNode(wrappedNode);
while (notMethod instanceof MethodCallExpr || notMethod instanceof FieldAccessExpr) {
notMethod = getParentNode(notMethod);
}
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(d -> Value.from(d))
.findFirst();
}
}
@@ -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.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
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 ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (Parameter parameter : wrappedNode.getParameters()) {
SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(parameter, typeSolver);
SymbolReference<? extends ValueDeclaration> 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<Type> 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 TypeVariable(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<TypeDeclaration> 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.getChildNodesByType(
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<MethodDeclaration> solveMethod(
String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
}
@@ -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.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.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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<MethodDeclaration> solveMethod(String name,
List<Type> argumentsTypes,
boolean staticOnly,
TypeSolver typeSolver) {
List<MethodDeclaration> candidateMethods =
myDeclaration
.getDeclaredMethods()
.stream()
.filter(m -> m.getName().equals(name) && (!staticOnly || m.isStatic()))
.collect(Collectors.toList());
if (!Object.class.getCanonicalName().equals(myDeclaration.getQualifiedName())) {
for (ReferenceType ancestor : myDeclaration.getAncestors()) {
SymbolReference<MethodDeclaration> 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<MethodDeclaration> 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<MethodDeclaration> 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<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
List<com.github.javaparser.ast.body.TypeDeclaration> typeDeclarations =
myDeclaration
.findMembersOfKind(com.github.javaparser.ast.body.TypeDeclaration.class);
Optional<SymbolReference<TypeDeclaration>> 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<TypeDeclaration>> 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<TypeDeclaration>> 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 (ReferenceType 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 (TypeDeclaration 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 ValueDeclaration> solveSymbol(String name,
TypeSolver typeSolver) {
Preconditions.checkArgument(typeSolver != null);
if (myDeclaration.hasVisibleField(name)) {
return SymbolReference.solved(myDeclaration.getVisibleField(name));
}
return getParent().solveSymbol(name, typeSolver);
}
}
@@ -0,0 +1,54 @@
package com.github.javaparser.symbolsolver.javaparsermodel.contexts;
import com.github.javaparser.ast.stmt.CatchClause;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.Type;
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 ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(wrappedNode.getParameter(), typeSolver);
SymbolReference<? extends ValueDeclaration> 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<MethodDeclaration> solveMethod(
String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
}
@@ -0,0 +1,108 @@
/*
* 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.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter;
import com.github.javaparser.symbolsolver.model.declarations.*;
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.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
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 ValueDeclaration> 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<Type> 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 TypeVariable(new JavaParserTypeParameter(tp, typeSolver)));
}
}
return getParent().solveGenericType(name, typeSolver);
}
@Override
public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
return javaParserTypeDeclarationAdapter.solveType(name, typeSolver);
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return javaParserTypeDeclarationAdapter.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
}
public SymbolReference<ConstructorDeclaration> solveConstructor(List<Type> argumentsTypes, TypeSolver typeSolver) {
return javaParserTypeDeclarationAdapter.solveConstructor(argumentsTypes, typeSolver);
}
///
/// Private methods
///
private ReferenceTypeDeclaration getDeclaration() {
return JavaParserFacade.get(typeSolver).getTypeDeclaration(this.wrappedNode);
}
}
@@ -0,0 +1,285 @@
/*
* 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.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.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnnotationDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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 ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
// solve absolute references
String itName = name;
while (itName.contains(".")) {
String typeName = getType(itName);
String memberName = getMember(itName);
SymbolReference<com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration> 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();
com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration importedType = typeSolver.solveType(qName);
SymbolReference<? extends ValueDeclaration> 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)) {
com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration importedType = typeSolver.solveType(typeName);
return new SymbolSolver(typeSolver).solveSymbolInType(importedType, memberName);
}
}
}
}
}
return SymbolReference.unsolved(ValueDeclaration.class);
}
@Override
public SymbolReference<com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration> 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 {
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<com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName);
if (ref.isSolved()) {
return SymbolReference.adapt(ref, com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration.class);
}
}
}
}
// look into type imports on demand
for (ImportDeclaration importDecl : wrappedNode.getImports()) {
if (importDecl.isAsterisk()) {
String qName = importDecl.getNameAsString() + "." + name;
SymbolReference<com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName);
if (ref.isSolved()) {
return SymbolReference.adapt(ref, com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration.class);
}
}
}
}
// Look in current package
if (this.wrappedNode.getPackageDeclaration().isPresent()) {
String qName = this.wrappedNode.getPackageDeclaration().get().getName().toString() + "." + name;
SymbolReference<com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName);
if (ref.isSolved()) {
return SymbolReference.adapt(ref, com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration.class);
}
} else {
// look for classes in the default package
String qName = name;
SymbolReference<com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName);
if (ref.isSolved()) {
return SymbolReference.adapt(ref, com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration.class);
}
}
// Look in the java.lang package
SymbolReference<com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration> ref = typeSolver.tryToSolveType("java.lang." + name);
if (ref.isSolved()) {
return SymbolReference.adapt(ref, com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration.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), com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration.class);
} else {
return SymbolReference.unsolved(com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration.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<MethodDeclaration> solveMethod(String name, List<Type> 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(MethodDeclaration.class);
}
com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration ref = typeSolver.solveType(importString);
SymbolReference<MethodDeclaration> 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);
com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration ref = typeSolver.solveType(typeName);
SymbolReference<MethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver);
if (method.isSolved()) {
return method;
}
}
}
}
}
return SymbolReference.unsolved(MethodDeclaration.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;
}
}
@@ -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);
}
}
@@ -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.contexts;
import com.github.javaparser.symbolsolver.core.resolution.Context;
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.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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(TypeDeclaration typeDeclaration, String name,
List<Type> argumentsTypes, TypeSolver typeSolver,
Context invokationContext, List<Type> 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);
}
throw new UnsupportedOperationException(typeDeclaration.toString());
}
}
@@ -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.body.EnumConstantDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumConstantDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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 ValueDeclaration> 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<com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
return javaParserTypeDeclarationAdapter.solveType(name, typeSolver);
}
@Override
public SymbolReference<com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return javaParserTypeDeclarationAdapter.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
}
///
/// Private methods
///
private ReferenceTypeDeclaration getDeclaration() {
return new JavaParserEnumDeclaration(this.wrappedNode, typeSolver);
}
}
@@ -0,0 +1,93 @@
/*
* 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.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.PrimitiveType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import java.util.List;
import java.util.Optional;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @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 ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
if (wrappedNode.getField().toString().equals(name)) {
if (wrappedNode.getScope() instanceof ThisExpr) {
Type typeOfThis = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
return new SymbolSolver(typeSolver).solveSymbolInType(typeOfThis.asReferenceType().getTypeDeclaration(), name);
}
}
return JavaParserFactory.getContext(getParentNode(wrappedNode), typeSolver).solveSymbol(name, typeSolver);
}
@Override
public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
return JavaParserFactory.getContext(getParentNode(wrappedNode), typeSolver).solveType(name, typeSolver);
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> parameterTypes, boolean staticOnly, TypeSolver typeSolver) {
return JavaParserFactory.getContext(getParentNode(wrappedNode), typeSolver).solveMethod(name, parameterTypes, false, typeSolver);
}
@Override
public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) {
Expression scope = wrappedNode.getScope();
if (wrappedNode.getField().toString().equals(name)) {
Type typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
if (typeOfScope.isArray() && name.equals(ARRAY_LENGTH_FIELD_NAME)) {
return Optional.of(new Value(PrimitiveType.INT, ARRAY_LENGTH_FIELD_NAME));
}
if (typeOfScope.isReferenceType()) {
Optional<Type> typeUsage = typeOfScope.asReferenceType().getFieldType(name);
if (typeUsage.isPresent()) {
return Optional.of(new Value(typeUsage.get(), name));
} else {
return Optional.empty();
}
} else {
return Optional.empty();
}
} else {
return getParent().solveSymbolAsValue(name, typeSolver);
}
}
}
@@ -0,0 +1,69 @@
/*
* 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.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.List;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
public class ForStatementContext extends AbstractJavaParserContext<ForStmt> {
public ForStatementContext(ForStmt wrappedNode, TypeSolver typeSolver) {
super(wrappedNode, typeSolver);
}
@Override
public SymbolReference<? extends ValueDeclaration> 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 (getParentNode(wrappedNode) instanceof NodeWithStatements) {
return StatementContext.solveInBlock(name, typeSolver, wrappedNode);
} else {
return getParent().solveSymbol(name, typeSolver);
}
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
}
@@ -0,0 +1,60 @@
/*
* 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.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.List;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
public class ForechStatementContext extends AbstractJavaParserContext<ForeachStmt> {
public ForechStatementContext(ForeachStmt wrappedNode, TypeSolver typeSolver) {
super(wrappedNode, typeSolver);
}
@Override
public SymbolReference<? extends ValueDeclaration> 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 (getParentNode(wrappedNode) instanceof BlockStmt) {
return StatementContext.solveInBlock(name, typeSolver, wrappedNode);
} else {
return getParent().solveSymbol(name, typeSolver);
}
}
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
}
@@ -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.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.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
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 ReferenceTypeDeclaration typeDeclaration;
public JavaParserTypeDeclarationAdapter(com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode, TypeSolver typeSolver,
ReferenceTypeDeclaration typeDeclaration,
Context context) {
this.wrappedNode = wrappedNode;
this.typeSolver = typeSolver;
this.typeDeclaration = typeDeclaration;
this.context = context;
}
public SymbolReference<TypeDeclaration> 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 (ReferenceType ancestor : this.typeDeclaration.getAncestors()) {
try {
for (TypeDeclaration 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<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
List<MethodDeclaration> 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 (ReferenceType ancestor : typeDeclaration.getAncestors()) {
// Avoid recursion on self
if (typeDeclaration != ancestor.getTypeDeclaration()) {
SymbolReference<MethodDeclaration> 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<MethodDeclaration> 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<MethodDeclaration> 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<ConstructorDeclaration> solveConstructor(List<Type> argumentsTypes, TypeSolver typeSolver) {
if (typeDeclaration instanceof ClassDeclaration) {
return ConstructorResolutionLogic.findMostApplicable(((ClassDeclaration) typeDeclaration).getConstructors(), argumentsTypes, typeSolver);
}
return SymbolReference.unsolved(ConstructorDeclaration.class);
}
}
@@ -0,0 +1,194 @@
/*
* 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.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.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
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.LambdaConstraintType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.reflectionmodel.MyObjectProvider;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import javaslang.Tuple2;
import java.util.*;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @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 (ValueDeclaration decl : sb.getSymbolDeclarations()) {
if (decl.getName().equals(name)) {
if (getParentNode(wrappedNode) instanceof MethodCallExpr) {
MethodCallExpr methodCallExpr = (MethodCallExpr) getParentNode(wrappedNode);
MethodUsage methodUsage = JavaParserFacade.get(typeSolver).solveMethodAsUsage(methodCallExpr);
int i = pos(methodCallExpr, wrappedNode);
Type 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
Type argType = inferenceContext.resolve(inferenceContext.addSingle(functionalMethod.getParamType(lambdaParamIndex)));
LambdaConstraintType conType;
if (argType.isWildcard()){
conType = LambdaConstraintType.bound(argType.asWildcard().getBoundedType());
} else {
conType = LambdaConstraintType.bound(argType);
}
Value value = new Value(conType, name);
return Optional.of(value);
} else{
return Optional.empty();
}
} else if (getParentNode(wrappedNode) instanceof VariableDeclarator) {
VariableDeclarator variableDeclarator = (VariableDeclarator) getParentNode(wrappedNode);
Type t = JavaParserFacade.get(typeSolver).convertToUsageVariableType(variableDeclarator);
Optional<MethodUsage> functionalMethod = FunctionalInterfaceLogic.getFunctionalMethod(t);
if (functionalMethod.isPresent()) {
Type lambdaType = functionalMethod.get().getParamType(index);
// Replace parameter from declarator
Map<TypeParameterDeclaration, Type> inferredTypes = new HashMap<>();
if (lambdaType.isReferenceType()) {
for (Tuple2<TypeParameterDeclaration, Type> entry : lambdaType.asReferenceType().getTypeParametersMap()) {
if (entry._2.isTypeVariable() && entry._2.asTypeParameter().declaredOnType()) {
Type ot = t.asReferenceType().typeParametersMap().getValue(entry._1);
lambdaType = lambdaType.replaceTypeVariables(entry._1, 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 ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (Parameter parameter : wrappedNode.getParameters()) {
SymbolDeclarator sb = JavaParserFactory.getSymbolDeclarator(parameter, typeSolver);
SymbolReference<ValueDeclaration> 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<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
return getParent().solveType(name, typeSolver);
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(
String name, List<Type> 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 (ValueDeclaration 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();
}
}
@@ -0,0 +1,476 @@
/*
* 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.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.resolution.Value;
import com.github.javaparser.symbolsolver.model.typesystem.*;
import com.github.javaparser.symbolsolver.model.typesystem.ArrayType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import javaslang.Tuple2;
import java.util.ArrayList;
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<Type> solveGenericType(String name, TypeSolver typeSolver) {
if(wrappedNode.getScope().isPresent()){
Type typeOfScope = JavaParserFacade.get(typeSolver).getType(wrappedNode.getScope().get());
Optional<Type> 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<Type> 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<TypeDeclaration> ref = solveType(className, typeSolver);
if (ref.isSolved()) {
SymbolReference<MethodDeclaration> 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);
}
}
}
Type typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
// we can replace the parameter types from the scope into the typeParametersValues
Map<TypeParameterDeclaration, Type> 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
Type originalArgumentType = argumentsTypes.get(i);
Type updatedArgumentType = usingParameterTypesFromScope(typeOfScope, originalArgumentType, inferredTypes);
argumentsTypes.set(i, updatedArgumentType);
}
for (int i = 0; i < argumentsTypes.size(); i++) {
Type 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<Type> typeArguments = new ArrayList<>();
for (com.github.javaparser.ast.type.Type ty : wrappedNode.getTypeArguments().get()) {
typeArguments.add(JavaParserFacade.get(typeSolver).convertToUsage(ty));
}
List<TypeParameterDeclaration> 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 ValueDeclaration> 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<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
if (wrappedNode.getScope().isPresent()) {
Expression scope = wrappedNode.getScope().get();
// consider static methods
if (scope instanceof NameExpr) {
NameExpr scopeAsName = (NameExpr) scope;
SymbolReference<TypeDeclaration> symbolReference = this.solveType(scopeAsName.getName().getId(), typeSolver);
if (symbolReference.isSolved() && symbolReference.getCorrespondingDeclaration().isType()) {
TypeDeclaration typeDeclaration = symbolReference.getCorrespondingDeclaration().asType();
return MethodResolutionLogic.solveMethodInType(typeDeclaration, name, argumentsTypes, false, typeSolver);
}
}
Type typeOfScope = null;
try {
typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
} catch (Exception e) {
throw new RuntimeException(String.format("Issue calculating the type of the scope of " + this), e);
}
if (typeOfScope.isWildcard()) {
if (typeOfScope.asWildcard().isExtends() || typeOfScope.asWildcard().isSuper()) {
return MethodResolutionLogic.solveMethodInType(typeOfScope.asWildcard().getBoundedType().asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
} else {
return MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver);
}
} else if (typeOfScope.isArray()) {
// method call on array are Object methods
return MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver);
} else if (typeOfScope.isTypeVariable()) {
for (TypeParameterDeclaration.Bound bound : typeOfScope.asTypeParameter().getBounds(typeSolver)) {
SymbolReference<MethodDeclaration> res = MethodResolutionLogic.solveMethodInType(bound.getType().asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
if (res.isSolved()) {
return res;
}
}
return SymbolReference.unsolved(MethodDeclaration.class);
} else if (typeOfScope.isConstraint()){
return MethodResolutionLogic.solveMethodInType(typeOfScope.asConstraintType().getBound().asReferenceType().getTypeDeclaration(), name, argumentsTypes, typeSolver);
} else {
return MethodResolutionLogic.solveMethodInType(typeOfScope.asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
}
} else {
Type typeOfScope = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
return MethodResolutionLogic.solveMethodInType(typeOfScope.asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
}
}
///
/// Private methods
///
private Optional<MethodUsage> solveMethodAsUsage(ReferenceType refType, String name,
List<Type> 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<TypeParameterDeclaration, Type> derivedValues = new HashMap<>();
for (int i = 0; i < methodUsage.getParamTypes().size(); i++) {
ParameterDeclaration parameter = methodUsage.getDeclaration().getParam(i);
Type parameterType = parameter.getType();
if (parameter.isVariadic()) {
parameterType = parameterType.asArrayType().getComponentType();
}
inferTypes(argumentsTypes.get(i), parameterType, derivedValues);
}
for (Map.Entry<TypeParameterDeclaration, Type> entry : derivedValues.entrySet()){
methodUsage = methodUsage.replaceTypeParameter(entry.getKey(), entry.getValue());
}
Type returnType = refType.useThisTypeParametersOnTheGivenType(methodUsage.returnType());
if (returnType != methodUsage.returnType()) {
methodUsage = methodUsage.replaceReturnType(returnType);
}
for (int i = 0; i < methodUsage.getParamTypes().size(); i++) {
Type replaced = refType.useThisTypeParametersOnTheGivenType(methodUsage.getParamTypes().get(i));
methodUsage = methodUsage.replaceParamType(i, replaced);
}
return Optional.of(methodUsage);
} else {
return ref;
}
}
private void inferTypes(Type source, Type target, Map<TypeParameterDeclaration, Type> mappings) {
if (source.equals(target)) {
return;
}
if (source.isReferenceType() && target.isReferenceType()) {
ReferenceType sourceRefType = source.asReferenceType();
ReferenceType 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<Type> actualParamTypes) {
Map<TypeParameterDeclaration, Type> matchedTypeParameters = new HashMap<>();
if (methodUsage.getDeclaration().hasVariadicParameter()) {
if (actualParamTypes.size() == methodUsage.getDeclaration().getNumberOfParams()) {
// the varargs parameter is an Array, so extract the inner type
Type expectedType =
methodUsage.getDeclaration().getLastParam().getType().asArrayType().getComponentType();
// the varargs corresponding type can be either T or Array<T>
Type actualType =
actualParamTypes.get(actualParamTypes.size() - 1).isArray() ?
actualParamTypes.get(actualParamTypes.size() - 1).asArrayType().getComponentType() :
actualParamTypes.get(actualParamTypes.size() - 1);
if (!expectedType.isAssignableBy(actualType)) {
for (TypeParameterDeclaration 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++) {
Type expectedType = methodUsage.getParamType(i);
Type actualType = actualParamTypes.get(i);
matchTypeParameters(expectedType, actualType, matchedTypeParameters);
}
for (TypeParameterDeclaration tp : matchedTypeParameters.keySet()) {
methodUsage = methodUsage.replaceTypeParameter(tp, matchedTypeParameters.get(tp));
}
return methodUsage;
}
private void matchTypeParameters(Type expectedType, Type actualType, Map<TypeParameterDeclaration, Type> 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 such as: "classX extends classY<Integer>"
if (actualType.asReferenceType().typeParametersValues().size() > 0) {
int i = 0;
for (Type 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(TypeVariable tp, String name, List<Type> argumentsTypes, TypeSolver typeSolver, Context invokationContext) {
for (TypeParameterDeclaration.Bound bound : tp.asTypeParameter().getBounds(typeSolver)) {
Optional<MethodUsage> methodUsage = solveMethodAsUsage(bound.getType(), name, argumentsTypes, typeSolver, invokationContext);
if (methodUsage.isPresent()) {
return methodUsage;
}
}
return Optional.empty();
}
private Optional<MethodUsage> solveMethodAsUsage(Type type, String name, List<Type> argumentsTypes, TypeSolver typeSolver, Context invokationContext) {
if (type instanceof ReferenceType) {
return solveMethodAsUsage((ReferenceType) type, name, argumentsTypes, typeSolver, invokationContext);
} else if (type instanceof TypeVariable) {
return solveMethodAsUsage((TypeVariable) type, name, argumentsTypes, typeSolver, invokationContext);
} else if (type instanceof Wildcard) {
Wildcard wildcardUsage = (Wildcard) 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 LambdaConstraintType){
LambdaConstraintType constraintType = (LambdaConstraintType) type;
return solveMethodAsUsage(constraintType.getBound(), name, argumentsTypes, typeSolver, invokationContext);
} else if (type instanceof ArrayType) {
// 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 Type usingParameterTypesFromScope(Type scope, Type type, Map<TypeParameterDeclaration, Type> inferredTypes) {
if (type.isReferenceType()) {
for (Tuple2<TypeParameterDeclaration, Type> entry : type.asReferenceType().getTypeParametersMap()) {
if (entry._1.declaredOnType() && scope.asReferenceType().getGenericParameterByName(entry._1.getName()).isPresent()) {
type = type.replaceTypeVariables(entry._1, scope.asReferenceType().getGenericParameterByName(entry._1.getName()).get(), inferredTypes);
}
}
return type;
} else {
return type;
}
}
private Type applyInferredTypes(Type type, Map<TypeParameterDeclaration, Type> inferredTypes) {
for (TypeParameterDeclaration tp : inferredTypes.keySet()) {
type = type.replaceTypeVariables(tp, inferredTypes.get(tp), inferredTypes);
}
return type;
}
}
@@ -0,0 +1,36 @@
/*
* 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);
}
}
@@ -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.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import java.util.List;
import java.util.Optional;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @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 ValueDeclaration> solveInBlock(String name, TypeSolver typeSolver, Statement stmt) {
if (!(getParentNode(stmt) instanceof NodeWithStatements)) {
throw new IllegalArgumentException();
}
NodeWithStatements<?> blockStmt = (NodeWithStatements<?>) getParentNode(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 ValueDeclaration> symbolReference = solveWith(symbolDeclarator, name);
if (symbolReference.isSolved()) {
return symbolReference;
}
}
// if nothing is found we should ask the parent context
return JavaParserFactory.getContext(getParentNode(stmt), typeSolver).solveSymbol(name, typeSolver);
}
public static Optional<Value> solveInBlockAsValue(String name, TypeSolver typeSolver, Statement stmt) {
if (!(getParentNode(stmt) instanceof NodeWithStatements)) {
throw new IllegalArgumentException();
}
NodeWithStatements<?> blockStmt = (NodeWithStatements<?>) getParentNode(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 ValueDeclaration> 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(getParentNode(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 (getParentNode(wrappedNode) instanceof com.github.javaparser.ast.body.MethodDeclaration) {
return getParent().solveSymbolAsValue(name, typeSolver);
}
if (getParentNode(wrappedNode) instanceof LambdaExpr) {
return getParent().solveSymbolAsValue(name, typeSolver);
}
if (getParentNode(wrappedNode) instanceof IfStmt) {
return getParent().solveSymbolAsValue(name, typeSolver);
}
if (!(getParentNode(wrappedNode) instanceof NodeWithStatements)) {
return getParent().solveSymbolAsValue(name, typeSolver);
}
NodeWithStatements<?> nodeWithStmt = (NodeWithStatements<?>) getParentNode(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 ValueDeclaration> 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 ValueDeclaration> symbolReference = solveWith(symbolDeclarator, name);
if (symbolReference.isSolved()) {
return symbolReference;
}
// we should look in all the statements preceding, treating them as SymbolDeclarators
if (getParentNode(wrappedNode) instanceof com.github.javaparser.ast.body.MethodDeclaration) {
return getParent().solveSymbol(name, typeSolver);
}
if (getParentNode(wrappedNode) instanceof com.github.javaparser.ast.body.ConstructorDeclaration) {
return getParent().solveSymbol(name, typeSolver);
}
if (getParentNode(wrappedNode) instanceof LambdaExpr) {
return getParent().solveSymbol(name, typeSolver);
}
if (!(getParentNode(wrappedNode) instanceof NodeWithStatements)) {
return getParent().solveSymbol(name, typeSolver);
}
NodeWithStatements<?> nodeWithStmt = (NodeWithStatements<?>) getParentNode(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<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
@Override
public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
return getParent().solveType(name, typeSolver);
}
}
@@ -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.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import java.util.List;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class SwitchEntryContext extends AbstractJavaParserContext<SwitchEntryStmt> {
public SwitchEntryContext(SwitchEntryStmt wrappedNode, TypeSolver typeSolver) {
super(wrappedNode, typeSolver);
}
@Override
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
SwitchStmt switchStmt = (SwitchStmt) getParentNode(wrappedNode);
Type 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 ValueDeclaration> symbolReference = solveWith(symbolDeclarator, name);
if (symbolReference.isSolved()) {
return symbolReference;
}
}
}
}
return getParent().solveSymbol(name, typeSolver);
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
}
@@ -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.VariableDeclarator;
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.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import java.util.List;
import java.util.Optional;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
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 (VariableDeclarationExpr expr : wrappedNode.getResources()) {
for (VariableDeclarator v : expr.getVariables()) {
if (v.getName().getIdentifier().equals(name)) {
JavaParserSymbolDeclaration decl = JavaParserSymbolDeclaration.localVar(v, typeSolver);
return Optional.of(Value.from(decl));
}
}
}
if (getParentNode(wrappedNode) instanceof BlockStmt) {
return StatementContext.solveInBlockAsValue(name, typeSolver, wrappedNode);
} else {
return getParent().solveSymbolAsValue(name, typeSolver);
}
}
@Override
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (VariableDeclarationExpr expr : wrappedNode.getResources()) {
for (VariableDeclarator v : expr.getVariables()) {
if (v.getName().getIdentifier().equals(name)) {
return SymbolReference.solved(JavaParserSymbolDeclaration.localVar(v, typeSolver));
}
}
}
if (getParentNode(wrappedNode) instanceof BlockStmt) {
return StatementContext.solveInBlock(name, typeSolver, wrappedNode);
} else {
return getParent().solveSymbol(name, typeSolver);
}
}
@Override
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
return getParent().solveMethod(name, argumentsTypes, false, typeSolver);
}
}
@@ -0,0 +1,64 @@
/*
* 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.symbolsolver.model.declarations.*;
import java.util.Collections;
import java.util.List;
/**
* @author Federico Tomassetti
*/
class DefaultConstructorDeclaration implements ConstructorDeclaration {
private ClassDeclaration classDeclaration;
DefaultConstructorDeclaration(ClassDeclaration classDeclaration) {
this.classDeclaration = classDeclaration;
}
@Override
public ClassDeclaration declaringType() {
return classDeclaration;
}
@Override
public int getNumberOfParams() {
return 0;
}
@Override
public ParameterDeclaration getParam(int i) {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return classDeclaration.getName();
}
@Override
public AccessLevel accessLevel() {
return AccessLevel.PUBLIC;
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return Collections.emptyList();
}
}
@@ -0,0 +1,89 @@
/*
* 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.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.AccessLevel;
import java.util.EnumSet;
import java.util.Optional;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
class Helper {
public static AccessLevel toAccessLevel(EnumSet<Modifier> modifiers) {
if (modifiers.contains(Modifier.PRIVATE)) {
return AccessLevel.PRIVATE;
} else if (modifiers.contains(Modifier.PROTECTED)) {
return AccessLevel.PROTECTED;
} else if (modifiers.contains(Modifier.PUBLIC)) {
return AccessLevel.PUBLIC;
} else {
return AccessLevel.PACKAGE_PROTECTED;
}
}
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(getParentNode(container));
}
return "";
}
static String getClassName(String base, Node container) {
if (container instanceof com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) {
String b = getClassName(base, getParentNode(container));
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, getParentNode(container));
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, getParentNode(container));
}
return base;
}
}
@@ -0,0 +1,92 @@
package com.github.javaparser.symbolsolver.javaparsermodel.declarations;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserAnnotationDeclaration extends AbstractTypeDeclaration implements AnnotationDeclaration {
private com.github.javaparser.ast.body.AnnotationDeclaration wrappedNode;
private TypeSolver typeSolver;
public JavaParserAnnotationDeclaration(com.github.javaparser.ast.body.AnnotationDeclaration wrappedNode, TypeSolver typeSolver) {
this.wrappedNode = wrappedNode;
this.typeSolver = typeSolver;
}
@Override
public List<ReferenceType> getAncestors() {
throw new UnsupportedOperationException();
}
@Override
public List<FieldDeclaration> getAllFields() {
throw new UnsupportedOperationException();
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAssignableBy(Type type) {
throw new UnsupportedOperationException();
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration 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(getParentNode(wrappedNode));
if (containerName.isEmpty()) {
return wrappedNode.getName().getId();
} else {
return containerName + "." + wrappedNode.getName();
}
}
@Override
public String getName() {
return wrappedNode.getName().getId();
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
throw new UnsupportedOperationException();
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
throw new UnsupportedOperationException("containerType is not supported for " + this.getClass().getCanonicalName());
}
}
@@ -0,0 +1,203 @@
package com.github.javaparser.symbolsolver.javaparsermodel.declarations;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.expr.ObjectCreationExpr;
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.declarations.AccessLevel;
import com.github.javaparser.symbolsolver.model.declarations.ConstructorDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.FieldDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
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 TypeDeclaration 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 TypeDeclaration getSuperTypeDeclaration() {
return superTypeDeclaration;
}
public <T extends Node> List<T> findMembersOfKind(final Class<T> memberClass) {
return wrappedNode
.getAnonymousClassBody()
.get()
.stream()
.filter(node -> memberClass.isAssignableFrom(node.getClass()))
.map(node -> (T) node)
.collect(Collectors.toList());
}
@Override
protected ReferenceType object() {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
@Override
public ReferenceType getSuperClass() {
return new ReferenceTypeImpl(superTypeDeclaration.asReferenceType(), typeSolver);
}
@Override
public List<ReferenceType> getInterfaces() {
return
superTypeDeclaration
.asReferenceType().getAncestors()
.stream()
.filter(type -> type.getTypeDeclaration().isInterface())
.collect(Collectors.toList());
}
@Override
public List<ConstructorDeclaration> getConstructors() {
return
findMembersOfKind(com.github.javaparser.ast.body.ConstructorDeclaration.class)
.stream()
.map(ctor -> new JavaParserConstructorDeclaration(this, ctor, typeSolver))
.collect(Collectors.toList());
}
@Override
public AccessLevel accessLevel() {
return AccessLevel.PRIVATE;
}
@Override
public List<ReferenceType> getAncestors() {
return
ImmutableList.
<ReferenceType>builder()
.add(getSuperClass())
.addAll(superTypeDeclaration.asReferenceType().getAncestors())
.build();
}
@Override
public List<FieldDeclaration> 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<FieldDeclaration> superClassFields =
getSuperClass().getTypeDeclaration().getAllFields();
List<FieldDeclaration> interfaceFields =
getInterfaces().stream()
.flatMap(inteface -> inteface.getTypeDeclaration().getAllFields().stream())
.collect(Collectors.toList());
return
ImmutableList
.<FieldDeclaration>builder()
.addAll(myFields)
.addAll(superClassFields)
.addAll(interfaceFields)
.build();
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return
findMembersOfKind(com.github.javaparser.ast.body.MethodDeclaration.class)
.stream()
.map(method -> new JavaParserMethodDeclaration(method, typeSolver))
.collect(Collectors.toSet());
}
@Override
public boolean isAssignableBy(Type type) {
return false;
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration 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(getParentNode(wrappedNode));
if (containerName.isEmpty()) {
return getName();
} else {
return containerName + "." + getName();
}
}
@Override
public Set<ReferenceTypeDeclaration> 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<TypeParameterDeclaration> getTypeParameters() {
return Lists.newArrayList();
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
throw new UnsupportedOperationException("containerType is not supported for " + this.getClass().getCanonicalName());
}
}
@@ -0,0 +1,381 @@
/*
* 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.*;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
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.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.declarations.ConstructorDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.FieldDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
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.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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<ClassOrInterfaceDeclaration>(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<FieldDeclaration> getAllFields() {
ArrayList<FieldDeclaration> fields = new ArrayList<>();
for (BodyDeclaration<?> member : 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));
}
}
}
ClassDeclaration superclass = (ClassDeclaration) this.getSuperClass().getTypeDeclaration();
if (superclass!=this)
fields.addAll(superclass.getAllFields());
getInterfaces().forEach(interf -> interf.getTypeDeclaration().getAllFields().forEach(f -> {
fields.add(f);
}));
return fields;
}
///
/// Public methods
///
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> parameterTypes) {
Context ctx = getContext();
return ctx.solveMethod(name, parameterTypes, false, typeSolver);
}
@Deprecated
public Context getContext() {
return JavaParserFactory.getContext(wrappedNode, typeSolver);
}
public Type getUsage(Node node) {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return wrappedNode.getName().getId();
}
@Override
public ReferenceType getSuperClass() {
if (wrappedNode.getExtendedTypes().isEmpty()) {
return object();
} else {
return toReferenceType(wrappedNode.getExtendedTypes().get(0));
}
}
@Override
public List<ReferenceType> getInterfaces() {
List<ReferenceType> interfaces = new ArrayList<>();
if (wrappedNode.getImplementedTypes() != null) {
for (ClassOrInterfaceType t : wrappedNode.getImplementedTypes()) {
interfaces.add(toReferenceType(t));
}
}
return interfaces;
}
@Override
public List<ConstructorDeclaration> getConstructors() {
List<ConstructorDeclaration> 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(ReferenceTypeDeclaration other) {
return javaParserTypeAdapter.isAssignableBy(other);
}
@Override
public boolean isAssignableBy(Type type) {
return javaParserTypeAdapter.isAssignableBy(type);
}
@Override
public boolean canBeAssignedTo(ReferenceTypeDeclaration other) {
// TODO consider generic types
if (this.getQualifiedName().equals(other.getQualifiedName())) {
return true;
}
ClassDeclaration superclass = (ClassDeclaration) 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()) {
ReferenceTypeDeclaration ancestor = (ReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type);
if (ancestor.canBeAssignedTo(other)) {
return true;
}
}
}
return false;
}
@Override
public boolean isTypeParameter() {
return false;
}
@Deprecated
public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
if (this.wrappedNode.getName().getId().equals(name)) {
return SymbolReference.solved(this);
}
SymbolReference<TypeDeclaration> 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<ReferenceType> getAncestors() {
List<ReferenceType> ancestors = new ArrayList<>();
ReferenceType superclass = getSuperClass();
if (superclass != null) {
ancestors.add(superclass);
}
if (wrappedNode.getImplementedTypes() != null) {
for (ClassOrInterfaceType implemented : wrappedNode.getImplementedTypes()) {
ReferenceType ancestor = toReferenceType(implemented);
ancestors.add(ancestor);
}
}
return ancestors;
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
Set<MethodDeclaration> 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<TypeParameterDeclaration> 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 AccessLevel accessLevel() {
return Helper.toAccessLevel(wrappedNode.getModifiers());
}
///
/// Protected methods
///
@Override
protected ReferenceType object() {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
Set<ReferenceTypeDeclaration> 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<ReferenceTypeDeclaration> containerType() {
return javaParserTypeAdapter.containerType();
}
///
/// Private methods
///
private ReferenceType 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<TypeDeclaration> 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<Type> 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);
}
}
@@ -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.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavaParserConstructorDeclaration implements ConstructorDeclaration {
private ClassDeclaration classDeclaration;
private com.github.javaparser.ast.body.ConstructorDeclaration wrappedNode;
private TypeSolver typeSolver;
public JavaParserConstructorDeclaration(ClassDeclaration classDeclaration, com.github.javaparser.ast.body.ConstructorDeclaration wrappedNode,
TypeSolver typeSolver) {
this.classDeclaration = classDeclaration;
this.wrappedNode = wrappedNode;
this.typeSolver = typeSolver;
}
@Override
public ClassDeclaration declaringType() {
return classDeclaration;
}
@Override
public int getNumberOfParams() {
return this.wrappedNode.getParameters().size();
}
@Override
public ParameterDeclaration 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 AccessLevel accessLevel() {
return Helper.toAccessLevel(wrappedNode.getModifiers());
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return this.wrappedNode.getTypeParameters().stream().map((astTp) -> new JavaParserTypeParameter(astTp, typeSolver)).collect(Collectors.toList());
}
}
@@ -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.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserEnumConstantDeclaration implements ValueDeclaration {
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 Type getType() {
return new ReferenceTypeImpl(new JavaParserEnumDeclaration((EnumDeclaration) getParentNode(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;
}
}
@@ -0,0 +1,340 @@
/*
* 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.BodyDeclaration;
import com.github.javaparser.ast.body.EnumConstantDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
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.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ArrayType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.model.typesystem.parametrization.TypeParametersMap;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionFactory;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import java.io.Serializable;
import java.util.*;
/**
* @author Federico Tomassetti
*/
public class JavaParserEnumDeclaration extends AbstractTypeDeclaration implements EnumDeclaration {
private TypeSolver typeSolver;
private com.github.javaparser.ast.body.EnumDeclaration wrappedNode;
private JavaParserTypeAdapter 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<MethodDeclaration> getDeclaredMethods() {
Set<MethodDeclaration> 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(ReferenceTypeDeclaration other) {
// Enums cannot be extended
if (other.getQualifiedName().equals(this.getQualifiedName())) {
return true;
}
if (other.getQualifiedName().equals(Enum.class.getCanonicalName())) {
return true;
}
// Enum implements Comparable and Serializable
if (other.getQualifiedName().equals(Comparable.class.getCanonicalName())) {
return true;
}
if (other.getQualifiedName().equals(Serializable.class.getCanonicalName())) {
return true;
}
if (other.getQualifiedName().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(ReferenceTypeDeclaration other) {
return javaParserTypeAdapter.isAssignableBy(other);
}
@Override
public boolean isAssignableBy(Type 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<Type> parameterTypes, TypeSolver typeSolver, Context invokationContext, List<Type> 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<FieldDeclaration> getAllFields() {
ArrayList<FieldDeclaration> fields = new ArrayList<>();
if (this.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));
}
}
}
}
if (this.wrappedNode.getEntries() != null) {
for (EnumConstantDeclaration member : this.wrappedNode.getEntries()) {
fields.add(new JavaParserFieldDeclaration(member, typeSolver));
}
}
return fields;
}
@Override
public List<ReferenceType> getAncestors() {
List<ReferenceType> ancestors = new ArrayList<>();
ReferenceType enumClass = ReflectionFactory.typeUsageFor(Enum.class, typeSolver).asReferenceType();
TypeParameterDeclaration eTypeParameter = enumClass.getTypeDeclaration().getTypeParameters().get(0);
enumClass = enumClass.deriveTypeParameters(new TypeParametersMap.Builder().setValue(eTypeParameter, new ReferenceTypeImpl(this, typeSolver)).build());
ancestors.add(enumClass);
if (wrappedNode.getImplementedTypes() != null) {
for (ClassOrInterfaceType implementedType : wrappedNode.getImplementedTypes()) {
SymbolReference<TypeDeclaration> implementedDeclRef = new SymbolSolver(typeSolver).solveTypeInType(this, implementedType.getName().getId());
if (!implementedDeclRef.isSolved()) {
throw new UnsolvedSymbolException(implementedType.getName().getId());
}
ancestors.add(new ReferenceTypeImpl((ReferenceTypeDeclaration) implementedDeclRef.getCorrespondingDeclaration(), typeSolver));
}
}
return ancestors;
}
@Override
public List<TypeParameterDeclaration> 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;
}
// Needed by ContextHelper
public static class ValuesMethod implements MethodDeclaration {
private JavaParserEnumDeclaration enumDeclaration;
private TypeSolver typeSolver;
public ValuesMethod(JavaParserEnumDeclaration enumDeclaration, TypeSolver typeSolver) {
this.enumDeclaration = enumDeclaration;
this.typeSolver = typeSolver;
}
@Override
public ReferenceTypeDeclaration declaringType() {
return enumDeclaration;
}
@Override
public Type getReturnType() {
return new ArrayType(new ReferenceTypeImpl(enumDeclaration, typeSolver));
}
@Override
public int getNumberOfParams() {
return 0;
}
@Override
public ParameterDeclaration getParam(int i) {
throw new UnsupportedOperationException();
}
public MethodUsage getUsage(Node node) {
throw new UnsupportedOperationException();
}
public MethodUsage resolveTypeVariables(Context context, List<Type> 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<TypeParameterDeclaration> getTypeParameters() {
return Collections.emptyList();
}
@Override
public AccessLevel accessLevel() {
return Helper.toAccessLevel(enumDeclaration.getWrappedNode().getModifiers());
}
}
@Override
public AccessLevel accessLevel() {
throw new UnsupportedOperationException();
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
Set<ReferenceTypeDeclaration> 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<ReferenceTypeDeclaration> containerType() {
return javaParserTypeAdapter.containerType();
}
}
@@ -0,0 +1,123 @@
/*
* 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.Modifier;
import com.github.javaparser.ast.body.EnumConstantDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.symbolsolver.javaparser.Navigator;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.declarations.AccessLevel;
import com.github.javaparser.symbolsolver.model.declarations.FieldDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.Optional;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserFieldDeclaration implements FieldDeclaration {
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 (!(getParentNode(variableDeclarator) instanceof com.github.javaparser.ast.body.FieldDeclaration)) {
throw new IllegalStateException(getParentNode(variableDeclarator).getClass().getCanonicalName());
}
this.wrappedNode = (com.github.javaparser.ast.body.FieldDeclaration) getParentNode(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 Type getType() {
if (enumConstantDeclaration != null) {
com.github.javaparser.ast.body.EnumDeclaration enumDeclaration = (com.github.javaparser.ast.body.EnumDeclaration) getParentNode(enumConstantDeclaration);
return new ReferenceTypeImpl(new JavaParserEnumDeclaration(enumDeclaration, typeSolver), typeSolver);
} else {
Type retType = JavaParserFacade.get(typeSolver).convert(variableDeclarator.getType(), wrappedNode);
return retType;
}
}
@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 AccessLevel accessLevel() {
return Helper.toAccessLevel(wrappedNode.getModifiers());
}
@Override
public TypeDeclaration declaringType() {
Optional<com.github.javaparser.ast.body.TypeDeclaration> typeDeclaration = Navigator.findAncestor(wrappedNode, com.github.javaparser.ast.body.TypeDeclaration.class);
if (typeDeclaration.isPresent()) {
return JavaParserFacade.get(typeSolver).getTypeDeclaration(typeDeclaration.get());
} else {
throw new IllegalStateException();
}
}
}
@@ -0,0 +1,319 @@
/*
* 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.BodyDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
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.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
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.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavaParserInterfaceDeclaration extends AbstractTypeDeclaration implements InterfaceDeclaration {
private TypeSolver typeSolver;
private ClassOrInterfaceDeclaration wrappedNode;
private JavaParserTypeAdapter 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<MethodDeclaration> getDeclaredMethods() {
Set<MethodDeclaration> 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 Type 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 InterfaceDeclaration 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<ReferenceType> getInterfacesExtended() {
List<ReferenceType> 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(ReferenceTypeDeclaration other) {
return javaParserTypeAdapter.isAssignableBy(other);
}
@Override
public boolean isAssignableBy(Type type) {
return javaParserTypeAdapter.isAssignableBy(type);
}
@Override
public boolean canBeAssignedTo(ReferenceTypeDeclaration other) {
// TODO consider generic types
if (this.getQualifiedName().equals(other.getQualifiedName())) {
return true;
}
if (this.wrappedNode.getExtendedTypes() != null) {
for (ClassOrInterfaceType type : wrappedNode.getExtendedTypes()) {
ReferenceTypeDeclaration ancestor = (ReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type);
if (ancestor.canBeAssignedTo(other)) {
return true;
}
}
}
if (this.wrappedNode.getImplementedTypes() != null) {
for (ClassOrInterfaceType type : wrappedNode.getImplementedTypes()) {
ReferenceTypeDeclaration ancestor = (ReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type);
if (ancestor.canBeAssignedTo(other)) {
return true;
}
}
}
return false;
}
@Override
public boolean isTypeParameter() {
return false;
}
@Override
public List<FieldDeclaration> getAllFields() {
ArrayList<FieldDeclaration> fields = new ArrayList<>();
for (BodyDeclaration member : 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));
}
}
}
getAncestors().forEach(a -> {
if (a.getTypeDeclaration() != this) {
fields.addAll(a.getTypeDeclaration().getAllFields());
}
});
return fields;
}
@Override
public String toString() {
return "JavaParserInterfaceDeclaration{" +
"wrappedNode=" + wrappedNode +
'}';
}
@Deprecated
public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
if (this.wrappedNode.getName().getId().equals(name)) {
return SymbolReference.solved(this);
}
SymbolReference<TypeDeclaration> 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<ReferenceType> getAncestors() {
List<ReferenceType> 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<TypeParameterDeclaration> 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 AccessLevel accessLevel() {
return Helper.toAccessLevel(wrappedNode.getModifiers());
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
Set<ReferenceTypeDeclaration> 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<ReferenceTypeDeclaration> containerType() {
return javaParserTypeAdapter.containerType();
}
///
/// Private methods
///
private ReferenceType toReferenceType(ClassOrInterfaceType classOrInterfaceType) {
SymbolReference<? extends TypeDeclaration> 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<Type> 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);
}
}
@@ -0,0 +1,149 @@
/*
* 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.expr.ObjectCreationExpr;
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.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.List;
import java.util.stream.Collectors;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserMethodDeclaration implements MethodDeclaration {
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 ReferenceTypeDeclaration declaringType() {
if (getParentNode(wrappedNode) instanceof ObjectCreationExpr) {
ObjectCreationExpr parentNode = (ObjectCreationExpr) getParentNode(wrappedNode);
return new JavaParserAnonymousClassDeclaration(parentNode, typeSolver);
} else {
return JavaParserFactory.toTypeDeclaration(getParentNode(wrappedNode), typeSolver);
}
}
@Override
public Type getReturnType() {
return JavaParserFacade.get(typeSolver).convert(wrappedNode.getType(), getContext());
}
@Override
public int getNumberOfParams() {
return wrappedNode.getParameters().size();
}
@Override
public ParameterDeclaration 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<Type> 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<TypeParameterDeclaration> 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 AccessLevel accessLevel() {
return Helper.toAccessLevel(wrappedNode.getModifiers());
}
}
@@ -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.declarations;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.declarations.ParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ArrayType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
/**
* @author Federico Tomassetti
*/
public class JavaParserParameterDeclaration implements ParameterDeclaration {
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 Type getType() {
Type res = JavaParserFacade.get(typeSolver).convert(wrappedNode.getType(), wrappedNode);
if (isVariadic()) {
res = new ArrayType(res);
}
return res;
}
@Override
public ParameterDeclaration 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;
}
}
@@ -0,0 +1,177 @@
/*
* 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.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ArrayType;
import com.github.javaparser.symbolsolver.model.typesystem.PrimitiveType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserSymbolDeclaration implements ValueDeclaration {
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 : getParentNode(parameter).getChildNodes()) {
if (node == parameter) {
return pos;
} else if (node instanceof Parameter) {
pos++;
}
}
return pos;
}
public static int getParamPos(Node node) {
if (getParentNode(node) instanceof MethodCallExpr) {
MethodCallExpr call = (MethodCallExpr) getParentNode(node);
for (int i = 0; i < call.getArguments().size(); i++) {
if (call.getArguments().get(i) == node) return i;
}
throw new IllegalStateException();
} else {
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 Type getType() {
if (wrappedNode instanceof Parameter) {
Parameter parameter = (Parameter) wrappedNode;
if (getParentNode(wrappedNode) instanceof LambdaExpr) {
int pos = getParamPos(parameter);
Type lambdaType = JavaParserFacade.get(typeSolver).getType(getParentNode(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 {
Type rawType = null;
if (parameter.getType() instanceof com.github.javaparser.ast.type.PrimitiveType) {
rawType = PrimitiveType.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 ArrayType(rawType);
} else {
return rawType;
}
}
} else if (wrappedNode instanceof VariableDeclarator) {
VariableDeclarator variableDeclarator = (VariableDeclarator) wrappedNode;
if (getParentNode(wrappedNode) instanceof VariableDeclarationExpr) {
Type type = JavaParserFacade.get(typeSolver).convert(variableDeclarator.getType(), JavaParserFactory.getContext(wrappedNode, typeSolver));
return type;
} else if (getParentNode(wrappedNode) instanceof FieldDeclaration) {
return JavaParserFacade.get(typeSolver).convert(variableDeclarator.getType(), JavaParserFactory.getContext(wrappedNode, typeSolver));
} else {
throw new UnsupportedOperationException(getParentNode(wrappedNode).getClass().getCanonicalName());
}
} else {
throw new UnsupportedOperationException(wrappedNode.getClass().getCanonicalName());
}
}
@Override
public TypeDeclaration 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;
}
}
@@ -0,0 +1,120 @@
package com.github.javaparser.symbolsolver.javaparsermodel.declarations;
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.body.EnumDeclaration;
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.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
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> & NodeWithTypeParameters<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(ReferenceTypeDeclaration other) {
List<ReferenceType> ancestorsOfOther = other.getAllAncestors();
ancestorsOfOther.add(new ReferenceTypeImpl(other, typeSolver));
for (ReferenceType ancestorOfOther : ancestorsOfOther) {
if (ancestorOfOther.getQualifiedName().equals(this.getQualifiedName())) {
return true;
}
}
return false;
}
public boolean isAssignableBy(Type type) {
if (type.isNull()) {
return true;
}
if (type.isReferenceType()) {
ReferenceTypeDeclaration other = typeSolver.solveType(type.describe());
return isAssignableBy(other);
} else {
throw new UnsupportedOperationException();
}
}
public SymbolReference<TypeDeclaration> solveType(String name, TypeSolver typeSolver) {
if (this.wrappedNode.getTypeParameters() != null) {
for (com.github.javaparser.ast.type.TypeParameter typeParameter : this.wrappedNode.getTypeParameters()) {
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(TypeDeclaration.class);
}
public Optional<ReferenceTypeDeclaration> containerType() {
Optional<Node> parent = wrappedNode.getParentNode();
return parent.isPresent() ?
Optional.of(JavaParserFactory.toTypeDeclaration(parent.get(), typeSolver)) :
Optional.empty();
}
}
@@ -0,0 +1,224 @@
/*
* 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.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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.getParentNode;
/**
* @author Federico Tomassetti
*/
public class JavaParserTypeParameter extends AbstractTypeDeclaration implements TypeParameterDeclaration {
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<MethodDeclaration> getDeclaredMethods() {
return Collections.emptySet();
}
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> 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(ReferenceTypeDeclaration other) {
return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
}
@Override
public String getContainerQualifiedName() {
TypeParametrizable container = getContainer();
if (container instanceof ReferenceTypeDeclaration) {
return ((ReferenceTypeDeclaration) container).getQualifiedName();
} else if (container instanceof JavaParserConstructorDeclaration) {
return ((JavaParserConstructorDeclaration) container).getQualifiedSignature();
} else {
return ((JavaParserMethodDeclaration) container).getQualifiedSignature();
}
}
@Override
public String getContainerId() {
TypeParametrizable container = getContainer();
if (container instanceof ReferenceTypeDeclaration) {
return ((ReferenceTypeDeclaration) container).getId();
} else if (container instanceof JavaParserConstructorDeclaration) {
return ((JavaParserConstructorDeclaration) container).getQualifiedSignature();
} else {
return ((JavaParserMethodDeclaration) container).getQualifiedSignature();
}
}
@Override
public TypeParametrizable getContainer() {
Node parentNode = getParentNode(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()) {
ReferenceTypeDeclaration 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(TypeSolver typeSolver) {
return wrappedNode.getTypeBound().stream().map((astB) -> toBound(astB, typeSolver)).collect(Collectors.toList());
}
private Bound toBound(ClassOrInterfaceType classOrInterfaceType, TypeSolver typeSolver) {
Type type = JavaParserFacade.get(typeSolver).convertToUsage(classOrInterfaceType, classOrInterfaceType);
Bound bound = Bound.extendsBound(type);
return bound;
}
public Context getContext() {
throw new UnsupportedOperationException();
}
public Type getUsage(Node node) {
throw new UnsupportedOperationException();
}
@Override
public boolean isAssignableBy(Type type) {
throw new UnsupportedOperationException();
}
@Override
public FieldDeclaration getField(String name) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasField(String name) {
return false;
}
@Override
public List<FieldDeclaration> getAllFields() {
return new ArrayList<>();
}
@Override
public List<ReferenceType> getAncestors() {
throw new UnsupportedOperationException();
}
@Override
public boolean isTypeParameter() {
return true;
}
@Override
public boolean hasDirectlyAnnotation(String canonicalName) {
throw new UnsupportedOperationException();
}
@Override
public List<TypeParameterDeclaration> 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<ReferenceTypeDeclaration> containerType() {
TypeParametrizable container = getContainer();
if (container instanceof ReferenceTypeDeclaration) {
return Optional.of((ReferenceTypeDeclaration) container);
}
return Optional.empty();
}
}
@@ -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.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.FieldDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
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(ReferenceTypeDeclaration 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<MethodDeclaration> solveMethod(String name, List<Type> parameterTypes) {
throw new UnsupportedOperationException();
}
public Type getUsage(Node node) {
throw new UnsupportedOperationException();
}
@Override
public boolean isAssignableBy(Type 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 FieldDeclaration getField(String name) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasField(String name) {
return false;
}
@Override
public List<FieldDeclaration> getAllFields() {
return new ArrayList<>();
}
@Override
public List<ReferenceType> getAncestors() {
throw new UnsupportedOperationException();
}
@Override
public Set<MethodDeclaration> 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<TypeParameterDeclaration> getTypeParameters() {
return Collections.emptyList();
}
public TypeParameterDeclaration 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<ReferenceTypeDeclaration> containerType() {
return asTypeParameter().containerType();
}
}
@@ -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;
}
}
@@ -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.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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<ValueDeclaration> getSymbolDeclarations() {
List<ValueDeclaration> symbols = new LinkedList<>();
for (VariableDeclarator v : wrappedNode.getVariables()) {
symbols.add(JavaParserSymbolDeclaration.field(v, typeSolver));
}
return symbols;
}
}
@@ -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.symbolsolver.model.declarations.ValueDeclaration;
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<ValueDeclaration> getSymbolDeclarations() {
return Collections.emptyList();
}
}
@@ -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.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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<ValueDeclaration> getSymbolDeclarations() {
List<ValueDeclaration> symbols = new LinkedList<>();
symbols.add(JavaParserSymbolDeclaration.parameter(wrappedNode, typeSolver));
return symbols;
}
}
@@ -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.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
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);
if (getParentNode(wrappedNode) instanceof FieldDeclaration) {
throw new IllegalArgumentException();
}
}
@Override
public List<ValueDeclaration> getSymbolDeclarations() {
List<ValueDeclaration> symbols = wrappedNode.getVariables().stream().map(
v -> JavaParserSymbolDeclaration.localVar(v, typeSolver)
).collect(
Collectors.toCollection(() -> new LinkedList<>()));
return symbols;
}
}
@@ -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;
@@ -0,0 +1,383 @@
/*
* 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.javassistmodel;
import com.github.javaparser.ast.Node;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute;
import javassist.bytecode.SyntheticAttribute;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavassistClassDeclaration extends AbstractClassDeclaration {
private CtClass ctClass;
private TypeSolver typeSolver;
private JavassistTypeDeclarationAdapter javassistTypeDeclarationAdapter;
public JavassistClassDeclaration(CtClass ctClass, TypeSolver typeSolver) {
if (ctClass == null) {
throw new IllegalArgumentException();
}
if (ctClass.isInterface() || ctClass.isAnnotation() || ctClass.isPrimitive() || ctClass.isEnum()) {
throw new IllegalArgumentException("Trying to instantiate a JavassistClassDeclaration with something which is not a class: " + ctClass.toString());
}
this.ctClass = ctClass;
this.typeSolver = typeSolver;
this.javassistTypeDeclarationAdapter = new JavassistTypeDeclarationAdapter(ctClass, typeSolver);
}
@Override
protected ReferenceType object() {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
@Override
public boolean hasDirectlyAnnotation(String canonicalName) {
throw new UnsupportedOperationException();
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return javassistTypeDeclarationAdapter.getDeclaredMethods();
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration other) {
return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JavassistClassDeclaration that = (JavassistClassDeclaration) o;
if (!ctClass.equals(that.ctClass)) return false;
return true;
}
@Override
public int hashCode() {
return ctClass.hashCode();
}
@Override
public String getPackageName() {
return ctClass.getPackageName();
}
@Override
public String getClassName() {
String className = ctClass.getName().replace('$', '.');
if (getPackageName() != null) {
return className.substring(getPackageName().length() + 1, className.length());
}
return className;
}
@Override
public String getQualifiedName() {
return ctClass.getName().replace('$', '.');
}
public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argumentsTypes, TypeSolver typeSolver,
Context invokationContext, List<Type> typeParameterValues) {
return JavassistUtils.getMethodUsage(ctClass, name, argumentsTypes, typeSolver, invokationContext);
}
@Deprecated
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (CtField field : ctClass.getDeclaredFields()) {
if (field.getName().equals(name)) {
return SymbolReference.solved(new JavassistFieldDeclaration(field, typeSolver));
}
}
try {
CtClass superClass = ctClass.getSuperclass();
if (superClass != null) {
SymbolReference<? extends ValueDeclaration> ref = new JavassistClassDeclaration(superClass, typeSolver).solveSymbol(name, typeSolver);
if (ref.isSolved()) {
return ref;
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
try {
for (CtClass interfaze : ctClass.getInterfaces()) {
SymbolReference<? extends ValueDeclaration> ref = new JavassistInterfaceDeclaration(interfaze, typeSolver).solveSymbol(name, typeSolver);
if (ref.isSolved()) {
return ref;
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return SymbolReference.unsolved(ValueDeclaration.class);
}
@Override
public List<ReferenceType> getAncestors() {
List<ReferenceType> ancestors = new LinkedList<>();
if (getSuperClass() != null) {
ancestors.add(getSuperClass());
}
ancestors.addAll(getInterfaces());
return ancestors;
}
@Deprecated
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly) {
List<MethodDeclaration> candidates = new ArrayList<>();
Predicate<CtMethod> staticOnlyCheck = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
for (CtMethod method : ctClass.getDeclaredMethods()) {
boolean isSynthetic = method.getMethodInfo().getAttribute(SyntheticAttribute.tag) != null;
boolean isNotBridge = (method.getMethodInfo().getAccessFlags() & AccessFlag.BRIDGE) == 0;
if (method.getName().equals(name) && !isSynthetic && isNotBridge && staticOnlyCheck.test(method)) {
candidates.add(new JavassistMethodDeclaration(method, typeSolver));
}
}
try {
CtClass superClass = ctClass.getSuperclass();
if (superClass != null) {
SymbolReference<MethodDeclaration> ref = new JavassistClassDeclaration(superClass, typeSolver).solveMethod(name, argumentsTypes, staticOnly);
if (ref.isSolved()) {
candidates.add(ref.getCorrespondingDeclaration());
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
try {
for (CtClass interfaze : ctClass.getInterfaces()) {
SymbolReference<MethodDeclaration> ref = new JavassistInterfaceDeclaration(interfaze, typeSolver).solveMethod(name, argumentsTypes, staticOnly);
if (ref.isSolved()) {
candidates.add(ref.getCorrespondingDeclaration());
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return MethodResolutionLogic.findMostApplicable(candidates, name, argumentsTypes, typeSolver);
}
public Type getUsage(Node node) {
return new ReferenceTypeImpl(this, typeSolver);
}
@Override
public boolean isAssignableBy(Type type) {
if (type.isNull()) {
return true;
}
if (type instanceof LambdaArgumentTypePlaceholder) {
return isFunctionalInterface();
}
// TODO look into generics
if (type.describe().equals(this.getQualifiedName())) {
return true;
}
try {
if (this.ctClass.getSuperclass() != null
&& new JavassistClassDeclaration(this.ctClass.getSuperclass(), typeSolver).isAssignableBy(type)) {
return true;
}
for (CtClass interfaze : ctClass.getInterfaces()) {
if (new JavassistInterfaceDeclaration(interfaze, typeSolver).isAssignableBy(type)) {
return true;
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return false;
}
@Override
public boolean isTypeParameter() {
return false;
}
@Override
public List<FieldDeclaration> getAllFields() {
return javassistTypeDeclarationAdapter.getDeclaredFields();
}
@Override
public String getName() {
String[] nameElements = ctClass.getSimpleName().replace('$', '.').split("\\.");
return nameElements[nameElements.length - 1];
}
@Override
public boolean isField() {
return false;
}
@Override
public boolean isParameter() {
return false;
}
@Override
public boolean isType() {
return true;
}
@Override
public boolean isClass() {
return !ctClass.isInterface();
}
@Override
public ReferenceType getSuperClass() {
try {
if (ctClass.getSuperclass() == null) {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
if (ctClass.getGenericSignature() == null) {
return new ReferenceTypeImpl(new JavassistClassDeclaration(ctClass.getSuperclass(), typeSolver), typeSolver);
}
SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature());
return JavassistUtils.signatureTypeToType(classSignature.getSuperClass(), typeSolver, this).asReferenceType();
} catch (NotFoundException e) {
throw new RuntimeException(e);
} catch (BadBytecode e) {
throw new RuntimeException(e);
}
}
@Override
public List<ReferenceType> getInterfaces() {
try {
if (ctClass.getGenericSignature() == null) {
return Arrays.stream(ctClass.getInterfaces())
.map(i -> new JavassistInterfaceDeclaration(i, typeSolver))
.map(i -> new ReferenceTypeImpl(i, typeSolver))
.collect(Collectors.toList());
} else {
SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature());
return Arrays.stream(classSignature.getInterfaces())
.map(i -> JavassistUtils.signatureTypeToType(i, typeSolver, this).asReferenceType())
.collect(Collectors.toList());
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
} catch (BadBytecode e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isInterface() {
return ctClass.isInterface();
}
@Override
public String toString() {
return "JavassistClassDeclaration {" + ctClass.getName() + '}';
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return javassistTypeDeclarationAdapter.getTypeParameters();
}
@Override
public AccessLevel accessLevel() {
return JavassistFactory.modifiersToAccessLevel(ctClass.getModifiers());
}
@Override
public List<ConstructorDeclaration> getConstructors() {
return javassistTypeDeclarationAdapter.getConstructors();
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
return javassistTypeDeclarationAdapter.containerType();
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
try {
/*
Get all internal types of the current class and get their corresponding ReferenceTypeDeclaration.
Finally, return them in a Set.
*/
return Arrays.stream(ctClass.getDeclaredClasses()).map(itype -> JavassistFactory.toTypeDeclaration(itype, typeSolver)).collect(Collectors.toSet());
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public ReferenceTypeDeclaration getInternalType(String name) {
/*
The name of the ReferenceTypeDeclaration could be composed of the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
*/
Optional<ReferenceTypeDeclaration> type =
this.internalTypes().stream().filter(f -> f.getName().endsWith(name)).findFirst();
return type.orElseThrow(() ->
new UnsolvedSymbolException("Internal type not found: " + name));
}
@Override
public boolean hasInternalType(String name) {
/*
The name of the ReferenceTypeDeclaration could be composed of the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
*/
return this.internalTypes().stream().anyMatch(f -> f.getName().endsWith(name));
}
}
@@ -0,0 +1,122 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import javassist.CtConstructor;
import javassist.NotFoundException;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Fred Lefévère-Laoide
*/
public class JavassistConstructorDeclaration implements ConstructorDeclaration {
private CtConstructor ctConstructor;
private TypeSolver typeSolver;
public JavassistConstructorDeclaration(CtConstructor ctConstructor, TypeSolver typeSolver) {
this.ctConstructor = ctConstructor;
this.typeSolver = typeSolver;
}
@Override
public String toString() {
return "JavassistMethodDeclaration{" +
"CtConstructor=" + ctConstructor +
'}';
}
@Override
public String getName() {
return ctConstructor.getName();
}
@Override
public boolean isField() {
return false;
}
@Override
public boolean isParameter() {
return false;
}
@Override
public boolean isType() {
return false;
}
@Override
public ClassDeclaration declaringType() {
return new JavassistClassDeclaration(ctConstructor.getDeclaringClass(), typeSolver);
}
@Override
public int getNumberOfParams() {
try {
return ctConstructor.getParameterTypes().length;
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public ParameterDeclaration getParam(int i) {
try {
boolean variadic = false;
if ((ctConstructor.getModifiers() & javassist.Modifier.VARARGS) > 0) {
variadic = i == (ctConstructor.getParameterTypes().length - 1);
}
if (ctConstructor.getGenericSignature() != null) {
SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctConstructor.getGenericSignature());
SignatureAttribute.Type signatureType = methodSignature.getParameterTypes()[i];
return new JavassistParameterDeclaration(JavassistUtils.signatureTypeToType(signatureType, typeSolver, this), typeSolver, variadic);
} else {
return new JavassistParameterDeclaration(ctConstructor.getParameterTypes()[i], typeSolver, variadic);
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
} catch (BadBytecode badBytecode) {
throw new RuntimeException(badBytecode);
}
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
try {
if (ctConstructor.getGenericSignature() == null) {
return Collections.emptyList();
}
SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctConstructor.getGenericSignature());
return Arrays.stream(methodSignature.getTypeParameters()).map((jasTp) -> new JavassistTypeParameter(jasTp, this, typeSolver)).collect(Collectors.toList());
} catch (BadBytecode badBytecode) {
throw new RuntimeException(badBytecode);
}
}
@Override
public AccessLevel accessLevel() {
return JavassistFactory.modifiersToAccessLevel(ctConstructor.getModifiers());
}
}
@@ -0,0 +1,231 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.SyntheticAttribute;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavassistEnumDeclaration extends AbstractTypeDeclaration implements EnumDeclaration {
private CtClass ctClass;
private TypeSolver typeSolver;
private JavassistTypeDeclarationAdapter javassistTypeDeclarationAdapter;
public JavassistEnumDeclaration(CtClass ctClass, TypeSolver typeSolver) {
if (ctClass == null) {
throw new IllegalArgumentException();
}
if (!ctClass.isEnum()) {
throw new IllegalArgumentException("Trying to instantiate a JavassistEnumDeclaration with something which is not an enum: " + ctClass.toString());
}
this.ctClass = ctClass;
this.typeSolver = typeSolver;
this.javassistTypeDeclarationAdapter = new JavassistTypeDeclarationAdapter(ctClass, typeSolver);
}
@Override
public AccessLevel accessLevel() {
return JavassistFactory.modifiersToAccessLevel(ctClass.getModifiers());
}
@Override
public String getPackageName() {
return ctClass.getPackageName();
}
@Override
public String getClassName() {
String name = ctClass.getName().replace('$', '.');
if (getPackageName() != null) {
return name.substring(getPackageName().length() + 1, name.length());
}
return name;
}
@Override
public String getQualifiedName() {
return ctClass.getName().replace('$', '.');
}
@Override
public List<ReferenceType> getAncestors() {
// Direct ancestors of an enum are java.lang.Enum and interfaces
List<ReferenceType> ancestors = new LinkedList<>();
try {
CtClass superClass = ctClass.getSuperclass();
if (superClass != null) {
Type superClassTypeUsage = JavassistFactory.typeUsageFor(superClass, typeSolver);
if (superClassTypeUsage.isReferenceType()) {
ancestors.add(superClassTypeUsage.asReferenceType());
}
}
for (CtClass interfaze : ctClass.getInterfaces()) {
Type interfazeTypeUsage = JavassistFactory.typeUsageFor(interfaze, typeSolver);
if (interfazeTypeUsage.isReferenceType()) {
ancestors.add(interfazeTypeUsage.asReferenceType());
}
}
} catch (NotFoundException e) {
throw new RuntimeException("Ancestor not found for " + ctClass.getName() + ".", e);
}
return ancestors;
}
@Override
public FieldDeclaration getField(String name) {
Optional<FieldDeclaration> field = javassistTypeDeclarationAdapter.getDeclaredFields().stream().filter(f -> f.getName().equals(name)).findFirst();
return field.orElseThrow(() -> new RuntimeException("Field " + name + " does not exist in " + ctClass.getName() + "."));
}
@Override
public boolean hasField(String name) {
return javassistTypeDeclarationAdapter.getDeclaredFields().stream().anyMatch(f -> f.getName().equals(name));
}
@Override
public List<FieldDeclaration> getAllFields() {
return javassistTypeDeclarationAdapter.getDeclaredFields();
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return javassistTypeDeclarationAdapter.getDeclaredMethods();
}
@Override
public boolean isAssignableBy(Type type) {
throw new UnsupportedOperationException();
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration other) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasDirectlyAnnotation(String canonicalName) {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
String[] nameElements = ctClass.getSimpleName().replace('$', '.').split("\\.");
return nameElements[nameElements.length - 1];
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return javassistTypeDeclarationAdapter.getTypeParameters();
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
return javassistTypeDeclarationAdapter.containerType();
}
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly) {
List<MethodDeclaration> candidates = new ArrayList<>();
Predicate<CtMethod> staticOnlyCheck = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
for (CtMethod method : ctClass.getDeclaredMethods()) {
boolean isSynthetic = method.getMethodInfo().getAttribute(SyntheticAttribute.tag) != null;
boolean isNotBridge = (method.getMethodInfo().getAccessFlags() & AccessFlag.BRIDGE) == 0;
if (method.getName().equals(name) && !isSynthetic && isNotBridge && staticOnlyCheck.test(method)) {
candidates.add(new JavassistMethodDeclaration(method, typeSolver));
}
}
try {
CtClass superClass = ctClass.getSuperclass();
if (superClass != null) {
SymbolReference<MethodDeclaration> ref = new JavassistClassDeclaration(superClass, typeSolver).solveMethod(name, argumentsTypes, staticOnly);
if (ref.isSolved()) {
candidates.add(ref.getCorrespondingDeclaration());
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return MethodResolutionLogic.findMostApplicable(candidates, name, argumentsTypes, typeSolver);
}
public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argumentsTypes, TypeSolver typeSolver, Context invokationContext, List<Type> typeParameterValues) {
return JavassistUtils.getMethodUsage(ctClass, name, argumentsTypes, typeSolver, invokationContext);
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
try {
/*
Get all internal types of the current class and get their corresponding ReferenceTypeDeclaration.
Finally, return them in a Set.
*/
return Arrays.stream(ctClass.getDeclaredClasses()).map(itype -> JavassistFactory.toTypeDeclaration(itype, typeSolver)).collect(Collectors.toSet());
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public ReferenceTypeDeclaration getInternalType(String name) {
/*
The name of the ReferenceTypeDeclaration could be composed on the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
*/
Optional<ReferenceTypeDeclaration> type =
this.internalTypes().stream().filter(f -> f.getName().endsWith(name)).findFirst();
return type.orElseThrow(() ->
new UnsolvedSymbolException("Internal type not found: " + name));
}
@Override
public boolean hasInternalType(String name) {
/*
The name of the ReferenceTypeDeclaration could be composed on the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
*/
return this.internalTypes().stream().anyMatch(f -> f.getName().endsWith(name));
}
}
@@ -0,0 +1,84 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.model.declarations.AccessLevel;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.*;
import javassist.CtClass;
import javassist.NotFoundException;
import java.lang.reflect.Modifier;
/**
* @author Federico Tomassetti
*/
public class JavassistFactory {
public static Type typeUsageFor(CtClass ctClazz, TypeSolver typeSolver) {
try {
if (ctClazz.isArray()) {
return new ArrayType(typeUsageFor(ctClazz.getComponentType(), typeSolver));
} else if (ctClazz.isPrimitive()) {
if (ctClazz.getName().equals("void")) {
return VoidType.INSTANCE;
} else {
return PrimitiveType.byName(ctClazz.getName());
}
} else {
if (ctClazz.isInterface()) {
return new ReferenceTypeImpl(new JavassistInterfaceDeclaration(ctClazz, typeSolver),
typeSolver);
} else if (ctClazz.isEnum()) {
return new ReferenceTypeImpl(new JavassistEnumDeclaration(ctClazz, typeSolver),
typeSolver);
} else {
return new ReferenceTypeImpl(new JavassistClassDeclaration(ctClazz, typeSolver),
typeSolver);
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
public static ReferenceTypeDeclaration toTypeDeclaration(CtClass ctClazz, TypeSolver typeSolver) {
if (ctClazz.isInterface()) {
return new JavassistInterfaceDeclaration(ctClazz, typeSolver);
} else if (ctClazz.isEnum()) {
return new JavassistEnumDeclaration(ctClazz, typeSolver);
} else if (ctClazz.isAnnotation()) {
throw new UnsupportedOperationException("CtClass of annotation not yet supported");
} else if (ctClazz.isArray()) {
throw new IllegalArgumentException("This method should not be called passing an array");
} else {
return new JavassistClassDeclaration(ctClazz, typeSolver);
}
}
static AccessLevel modifiersToAccessLevel(final int modifiers) {
if (Modifier.isPublic(modifiers)) {
return AccessLevel.PUBLIC;
} else if (Modifier.isProtected(modifiers)) {
return AccessLevel.PROTECTED;
} else if (Modifier.isPrivate(modifiers)) {
return AccessLevel.PRIVATE;
} else {
return AccessLevel.PACKAGE_PROTECTED;
}
}
}
@@ -0,0 +1,84 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.model.declarations.AccessLevel;
import com.github.javaparser.symbolsolver.model.declarations.FieldDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import javassist.CtField;
import javassist.NotFoundException;
import java.lang.reflect.Modifier;
/**
* @author Federico Tomassetti
*/
public class JavassistFieldDeclaration implements FieldDeclaration {
private CtField ctField;
private TypeSolver typeSolver;
public JavassistFieldDeclaration(CtField ctField, TypeSolver typeSolver) {
this.ctField = ctField;
this.typeSolver = typeSolver;
}
@Override
public Type getType() {
try {
return JavassistFactory.typeUsageFor(ctField.getType(), typeSolver);
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isStatic() {
return Modifier.isStatic(ctField.getModifiers());
}
@Override
public String getName() {
return ctField.getName();
}
@Override
public boolean isField() {
return true;
}
@Override
public boolean isParameter() {
return false;
}
@Override
public boolean isType() {
return false;
}
@Override
public AccessLevel accessLevel() {
return JavassistFactory.modifiersToAccessLevel(ctField.getModifiers());
}
@Override
public TypeDeclaration declaringType() {
return JavassistFactory.toTypeDeclaration(ctField.getDeclaringClass(), typeSolver);
}
}
@@ -0,0 +1,280 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.SyntheticAttribute;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavassistInterfaceDeclaration extends AbstractTypeDeclaration implements InterfaceDeclaration {
private CtClass ctClass;
private TypeSolver typeSolver;
private JavassistTypeDeclarationAdapter javassistTypeDeclarationAdapter;
@Override
public String toString() {
return "JavassistInterfaceDeclaration{" +
"ctClass=" + ctClass.getName() +
", typeSolver=" + typeSolver +
'}';
}
public JavassistInterfaceDeclaration(CtClass ctClass, TypeSolver typeSolver) {
if (!ctClass.isInterface()) {
throw new IllegalArgumentException("Not an interface: " + ctClass.getName());
}
this.ctClass = ctClass;
this.typeSolver = typeSolver;
this.javassistTypeDeclarationAdapter = new JavassistTypeDeclarationAdapter(ctClass, typeSolver);
}
@Override
public List<ReferenceType> getInterfacesExtended() {
try {
return Arrays.stream(ctClass.getInterfaces()).map(i -> new JavassistInterfaceDeclaration(i, typeSolver))
.map(i -> new ReferenceTypeImpl(i, typeSolver)).collect(Collectors.toList());
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public String getPackageName() {
return ctClass.getPackageName();
}
@Override
public String getClassName() {
String className = ctClass.getName().replace('$', '.');
if (getPackageName() != null) {
return className.substring(getPackageName().length() + 1, className.length());
}
return className;
}
@Override
public String getQualifiedName() {
return ctClass.getName().replace('$', '.');
}
@Deprecated
public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argumentsTypes, TypeSolver typeSolver,
Context invokationContext, List<Type> typeParameterValues) {
return JavassistUtils.getMethodUsage(ctClass, name, argumentsTypes, typeSolver, invokationContext);
}
@Deprecated
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly) {
List<MethodDeclaration> candidates = new ArrayList<>();
Predicate<CtMethod> staticOnlyCheck = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
for (CtMethod method : ctClass.getDeclaredMethods()) {
boolean isSynthetic = method.getMethodInfo().getAttribute(SyntheticAttribute.tag) != null;
boolean isNotBridge = (method.getMethodInfo().getAccessFlags() & AccessFlag.BRIDGE) == 0;
if (method.getName().equals(name) && !isSynthetic && isNotBridge && staticOnlyCheck.test(method)) {
candidates.add(new JavassistMethodDeclaration(method, typeSolver));
}
}
try {
CtClass superClass = ctClass.getSuperclass();
if (superClass != null) {
SymbolReference<MethodDeclaration> ref = new JavassistClassDeclaration(superClass, typeSolver).solveMethod(name, argumentsTypes, staticOnly);
if (ref.isSolved()) {
candidates.add(ref.getCorrespondingDeclaration());
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
try {
for (CtClass interfaze : ctClass.getInterfaces()) {
SymbolReference<MethodDeclaration> ref = new JavassistInterfaceDeclaration(interfaze, typeSolver).solveMethod(name, argumentsTypes, staticOnly);
if (ref.isSolved()) {
candidates.add(ref.getCorrespondingDeclaration());
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return MethodResolutionLogic.findMostApplicable(candidates, name, argumentsTypes, typeSolver);
}
@Override
public boolean isAssignableBy(Type type) {
throw new UnsupportedOperationException();
}
@Override
public List<FieldDeclaration> getAllFields() {
return javassistTypeDeclarationAdapter.getDeclaredFields();
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration other) {
throw new UnsupportedOperationException();
}
@Override
public List<ReferenceType> getAncestors() {
List<ReferenceType> ancestors = new ArrayList<>();
try {
for (CtClass interfaze : ctClass.getInterfaces()) {
ReferenceType superInterfaze = JavassistFactory.typeUsageFor(interfaze, typeSolver).asReferenceType();
ancestors.add(superInterfaze);
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
ancestors = ancestors.stream().filter(a -> a.getQualifiedName() != Object.class.getCanonicalName())
.collect(Collectors.toList());
ancestors.add(new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
return ancestors;
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return Arrays.stream(ctClass.getDeclaredMethods())
.map(m -> new JavassistMethodDeclaration(m, typeSolver))
.collect(Collectors.toSet());
}
@Override
public boolean hasDirectlyAnnotation(String canonicalName) {
try {
for (Object annotationRaw : ctClass.getAnnotations()) {
if (annotationRaw.getClass().getCanonicalName().equals(canonicalName)) {
return true;
}
if (Arrays.stream(annotationRaw.getClass().getInterfaces()).anyMatch(it -> it.getCanonicalName().equals(canonicalName))) {
return true;
}
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return false;
}
@Override
public String getName() {
String[] nameElements = ctClass.getSimpleName().replace('$', '.').split("\\.");
return nameElements[nameElements.length - 1];
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return javassistTypeDeclarationAdapter.getTypeParameters();
}
@Override
public AccessLevel accessLevel() {
return JavassistFactory.modifiersToAccessLevel(ctClass.getModifiers());
}
@Override
public InterfaceDeclaration asInterface() {
return this;
}
@Deprecated
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (CtField field : ctClass.getDeclaredFields()) {
if (field.getName().equals(name)) {
return SymbolReference.solved(new JavassistFieldDeclaration(field, typeSolver));
}
}
try {
for (CtClass interfaze : ctClass.getInterfaces()) {
SymbolReference<? extends ValueDeclaration> ref = new JavassistInterfaceDeclaration(interfaze, typeSolver).solveSymbol(name, typeSolver);
if (ref.isSolved()) {
return ref;
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return SymbolReference.unsolved(ValueDeclaration.class);
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
return javassistTypeDeclarationAdapter.containerType();
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
try {
/*
Get all internal types of the current class and get their corresponding ReferenceTypeDeclaration.
Finally, return them in a Set.
*/
return Arrays.stream(ctClass.getDeclaredClasses()).map(itype -> JavassistFactory.toTypeDeclaration(itype, typeSolver)).collect(Collectors.toSet());
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public ReferenceTypeDeclaration getInternalType(String name) {
/*
The name of the ReferenceTypeDeclaration could be composed on the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
*/
Optional<ReferenceTypeDeclaration> type =
this.internalTypes().stream().filter(f -> f.getName().endsWith(name)).findFirst();
return type.orElseThrow(() ->
new UnsolvedSymbolException("Internal type not found: " + name));
}
@Override
public boolean hasInternalType(String name) {
/*
The name of the ReferenceTypeDeclaration could be composed on the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
*/
return this.internalTypes().stream().anyMatch(f -> f.getName().endsWith(name));
}
}
@@ -0,0 +1,165 @@
/*
* 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.javassistmodel;
import com.github.javaparser.ast.Node;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.declarations.common.MethodDeclarationCommonLogic;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavassistMethodDeclaration implements MethodDeclaration {
private CtMethod ctMethod;
private TypeSolver typeSolver;
public JavassistMethodDeclaration(CtMethod ctMethod, TypeSolver typeSolver) {
this.ctMethod = ctMethod;
this.typeSolver = typeSolver;
}
@Override
public boolean isDefaultMethod() {
return ctMethod.getDeclaringClass().isInterface() && !isAbstract();
}
@Override
public boolean isStatic() {
return Modifier.isStatic(ctMethod.getModifiers());
}
@Override
public String toString() {
return "JavassistMethodDeclaration{" +
"ctMethod=" + ctMethod +
'}';
}
@Override
public String getName() {
return ctMethod.getName();
}
@Override
public boolean isField() {
return false;
}
@Override
public boolean isParameter() {
return false;
}
@Override
public boolean isType() {
return false;
}
@Override
public ReferenceTypeDeclaration declaringType() {
if (ctMethod.getDeclaringClass().isInterface()) {
return new JavassistInterfaceDeclaration(ctMethod.getDeclaringClass(), typeSolver);
} else {
return new JavassistClassDeclaration(ctMethod.getDeclaringClass(), typeSolver);
}
}
@Override
public Type getReturnType() {
try {
return JavassistFactory.typeUsageFor(ctMethod.getReturnType(), typeSolver);
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public int getNumberOfParams() {
try {
return ctMethod.getParameterTypes().length;
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public ParameterDeclaration getParam(int i) {
try {
boolean variadic = false;
if ((ctMethod.getModifiers() & javassist.Modifier.VARARGS) > 0) {
variadic = i == (ctMethod.getParameterTypes().length - 1);
}
if (ctMethod.getGenericSignature() != null) {
SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctMethod.getGenericSignature());
SignatureAttribute.Type signatureType = methodSignature.getParameterTypes()[i];
return new JavassistParameterDeclaration(JavassistUtils.signatureTypeToType(signatureType, typeSolver, this), typeSolver, variadic);
} else {
return new JavassistParameterDeclaration(ctMethod.getParameterTypes()[i], typeSolver, variadic);
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
} catch (BadBytecode badBytecode) {
throw new RuntimeException(badBytecode);
}
}
public MethodUsage getUsage(Node node) {
throw new UnsupportedOperationException();
}
public MethodUsage resolveTypeVariables(Context context, List<Type> parameterTypes) {
return new MethodDeclarationCommonLogic(this, typeSolver).resolveTypeVariables(context, parameterTypes);
}
@Override
public boolean isAbstract() {
return Modifier.isAbstract(ctMethod.getModifiers());
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
try {
if (ctMethod.getGenericSignature() == null) {
return Collections.emptyList();
}
SignatureAttribute.MethodSignature methodSignature = SignatureAttribute.toMethodSignature(ctMethod.getGenericSignature());
return Arrays.stream(methodSignature.getTypeParameters()).map((jasTp) -> new JavassistTypeParameter(jasTp, this, typeSolver)).collect(Collectors.toList());
} catch (BadBytecode badBytecode) {
throw new RuntimeException(badBytecode);
}
}
@Override
public AccessLevel accessLevel() {
throw new UnsupportedOperationException();
}
}
@@ -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.javassistmodel;
import com.github.javaparser.symbolsolver.model.declarations.ParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import javassist.CtClass;
/**
* @author Federico Tomassetti
*/
public class JavassistParameterDeclaration implements ParameterDeclaration {
private Type type;
private TypeSolver typeSolver;
private boolean variadic;
public JavassistParameterDeclaration(CtClass type, TypeSolver typeSolver, boolean variadic) {
this(JavassistFactory.typeUsageFor(type, typeSolver), typeSolver, variadic);
}
public JavassistParameterDeclaration(Type type, TypeSolver typeSolver, boolean variadic) {
this.type = type;
this.typeSolver = typeSolver;
this.variadic = variadic;
}
@Override
public String toString() {
return "JavassistParameterDeclaration{" +
"type=" + type +
", typeSolver=" + typeSolver +
", variadic=" + variadic +
'}';
}
@Override
public String getName() {
throw new UnsupportedOperationException();
}
@Override
public boolean isField() {
throw new UnsupportedOperationException();
}
@Override
public boolean isParameter() {
throw new UnsupportedOperationException();
}
@Override
public boolean isVariadic() {
return variadic;
}
@Override
public boolean isType() {
throw new UnsupportedOperationException();
}
@Override
public Type getType() {
return type;
}
}
@@ -0,0 +1,93 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavassistTypeDeclarationAdapter {
private CtClass ctClass;
private TypeSolver typeSolver;
public JavassistTypeDeclarationAdapter(CtClass ctClass, TypeSolver typeSolver) {
this.ctClass = ctClass;
this.typeSolver = typeSolver;
}
public Set<MethodDeclaration> getDeclaredMethods() {
return Arrays.stream(ctClass.getDeclaredMethods())
.map(m -> new JavassistMethodDeclaration(m, typeSolver)).collect(Collectors.toSet());
}
public List<ConstructorDeclaration> getConstructors() {
return Arrays.stream(ctClass.getConstructors())
.map(m -> new JavassistConstructorDeclaration(m, typeSolver)).collect(Collectors.toList());
}
public List<FieldDeclaration> getDeclaredFields() {
List<FieldDeclaration> fieldDecls = new ArrayList<>();
collectDeclaredFields(ctClass, fieldDecls);
return fieldDecls;
}
private void collectDeclaredFields(CtClass ctClass, List<FieldDeclaration> fieldDecls) {
if (ctClass != null) {
Arrays.stream(ctClass.getDeclaredFields())
.forEach(f -> fieldDecls.add(new JavassistFieldDeclaration(f, typeSolver)));
try {
collectDeclaredFields(ctClass.getSuperclass(), fieldDecls);
} catch (NotFoundException e) {
// We'll stop here
}
}
}
public List<TypeParameterDeclaration> getTypeParameters() {
if (null == ctClass.getGenericSignature()) {
return Collections.emptyList();
} else {
try {
SignatureAttribute.ClassSignature classSignature =
SignatureAttribute.toClassSignature(ctClass.getGenericSignature());
return Arrays.<SignatureAttribute.TypeParameter>stream(classSignature.getParameters())
.map((tp) -> new JavassistTypeParameter(tp, JavassistFactory.toTypeDeclaration(ctClass, typeSolver), typeSolver))
.collect(Collectors.toList());
} catch (BadBytecode badBytecode) {
throw new RuntimeException(badBytecode);
}
}
}
public Optional<ReferenceTypeDeclaration> containerType() {
try {
return ctClass.getDeclaringClass() == null ?
Optional.empty() :
Optional.of(JavassistFactory.toTypeDeclaration(ctClass.getDeclaringClass(), typeSolver));
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,117 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.model.declarations.MethodLikeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParametrizable;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import javassist.bytecode.SignatureAttribute;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author Federico Tomassetti
*/
public class JavassistTypeParameter implements TypeParameterDeclaration {
private SignatureAttribute.TypeParameter wrapped;
private TypeSolver typeSolver;
private TypeParametrizable container;
public JavassistTypeParameter(SignatureAttribute.TypeParameter wrapped, TypeParametrizable container, TypeSolver typeSolver) {
this.wrapped = wrapped;
this.typeSolver = typeSolver;
this.container = container;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TypeParameterDeclaration)) return false;
TypeParameterDeclaration that = (TypeParameterDeclaration) o;
if (!getQualifiedName().equals(that.getQualifiedName())) {
return false;
}
if (declaredOnType() != that.declaredOnType()) {
return false;
}
if (declaredOnMethod() != that.declaredOnMethod()) {
return false;
}
// TODO check bounds
return true;
}
@Override
public String toString() {
return "JavassistTypeParameter{" +
wrapped.getName()
+ '}';
}
@Override
public String getName() {
return wrapped.getName();
}
@Override
public String getContainerQualifiedName() {
if (this.container instanceof ReferenceTypeDeclaration) {
return ((ReferenceTypeDeclaration) this.container).getQualifiedName();
} else if (this.container instanceof MethodLikeDeclaration) {
return ((MethodLikeDeclaration) this.container).getQualifiedName();
}
throw new UnsupportedOperationException();
}
@Override
public String getContainerId() {
return getContainerQualifiedName();
}
@Override
public TypeParametrizable getContainer() {
return this.container;
}
@Override
public List<TypeParameterDeclaration.Bound> getBounds(TypeSolver typeSolver) {
List<Bound> bounds = new ArrayList<>();
if (wrapped.getClassBound() != null && !wrapped.getClassBound().toString().equals(Object.class.getCanonicalName())) {
throw new UnsupportedOperationException(wrapped.getClassBound().toString());
}
for (SignatureAttribute.ObjectType ot : wrapped.getInterfaceBound()) {
throw new UnsupportedOperationException(ot.toString());
}
return bounds;
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
if (container instanceof ReferenceTypeDeclaration) {
return Optional.of((ReferenceTypeDeclaration) container);
}
return Optional.empty();
}
}
@@ -0,0 +1,177 @@
/*
* 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.javassistmodel;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParametrizable;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.typesystem.*;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
class JavassistUtils {
static Optional<MethodUsage> getMethodUsage(CtClass ctClass, String name, List<Type> argumentsTypes, TypeSolver typeSolver, Context invokationContext) {
// TODO avoid bridge and synthetic methods
for (CtMethod method : ctClass.getDeclaredMethods()) {
if (method.getName().equals(name)) {
// TODO check typeParametersValues
MethodUsage methodUsage = new MethodUsage(new JavassistMethodDeclaration(method, typeSolver));
if (argumentsTypes.size() < methodUsage.getNoParams()) {
// this method cannot be a good candidate (except if variadic ?)
continue;
}
try {
if (method.getGenericSignature() != null) {
SignatureAttribute.MethodSignature classSignature = SignatureAttribute.toMethodSignature(method.getGenericSignature());
List<Type> parametersOfReturnType = parseTypeParameters(classSignature.getReturnType().toString(), typeSolver, invokationContext);
Type newReturnType = methodUsage.returnType();
// consume one parametersOfReturnType at the time
if (!(newReturnType instanceof VoidType)) {
newReturnType = newReturnType.asReferenceType().transformTypeParameters(tp -> parametersOfReturnType.remove(0));
}
methodUsage = methodUsage.replaceReturnType(newReturnType);
}
return Optional.of(methodUsage);
} catch (BadBytecode e) {
throw new RuntimeException(e);
}
}
}
try {
CtClass superClass = ctClass.getSuperclass();
if (superClass != null) {
Optional<MethodUsage> ref = new JavassistClassDeclaration(superClass, typeSolver).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, null);
if (ref.isPresent()) {
return ref;
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
try {
for (CtClass interfaze : ctClass.getInterfaces()) {
Optional<MethodUsage> ref = new JavassistInterfaceDeclaration(interfaze, typeSolver).solveMethodAsUsage(name, argumentsTypes, typeSolver, invokationContext, null);
if (ref.isPresent()) {
return ref;
}
}
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return Optional.empty();
}
private static List<Type> parseTypeParameters(String signature, TypeSolver typeSolver, Context invokationContext) {
String originalSignature = signature;
if (signature.contains("<")) {
signature = signature.substring(signature.indexOf('<') + 1);
if (!signature.endsWith(">")) {
throw new IllegalArgumentException();
}
signature = signature.substring(0, signature.length() - 1);
if (signature.contains(",")) {
throw new UnsupportedOperationException();
}
if (signature.contains("<")) {
throw new UnsupportedOperationException(originalSignature);
}
if (signature.contains(">")) {
throw new UnsupportedOperationException();
}
List<Type> types = new ArrayList<>();
types.add(new SymbolSolver(typeSolver).solveTypeUsage(signature, invokationContext));
return types;
} else {
return Collections.emptyList();
}
}
static Type signatureTypeToType(SignatureAttribute.Type signatureType, TypeSolver typeSolver, TypeParametrizable typeParametrizable) {
if (signatureType instanceof SignatureAttribute.ClassType) {
SignatureAttribute.ClassType classType = (SignatureAttribute.ClassType) signatureType;
List<Type> typeParameters = classType.getTypeArguments() == null ? Collections.emptyList() : Arrays.stream(classType.getTypeArguments()).map(ta -> typeArgumentToType(ta, typeSolver, typeParametrizable)).collect(Collectors.toList());
final String typeName =
classType.getDeclaringClass() != null ?
classType.getDeclaringClass().getName() + "." + classType.getName() :
classType.getName();
ReferenceTypeDeclaration typeDeclaration = typeSolver.solveType(
internalNameToCanonicalName(typeName));
return new ReferenceTypeImpl(typeDeclaration, typeParameters, typeSolver);
} else if (signatureType instanceof SignatureAttribute.TypeVariable) {
SignatureAttribute.TypeVariable typeVariableSignature = (SignatureAttribute.TypeVariable)signatureType;
Optional<TypeParameterDeclaration> typeParameterDeclarationOpt = typeParametrizable.findTypeParameter(typeVariableSignature.getName());
if (!typeParameterDeclarationOpt.isPresent()) {
throw new UnsolvedSymbolException("Unable to solve TypeVariable " + typeVariableSignature);
}
TypeParameterDeclaration typeParameterDeclaration = typeParameterDeclarationOpt.get();
return new TypeVariable(typeParameterDeclaration);
} else {
throw new RuntimeException(signatureType.getClass().getCanonicalName());
}
}
private static String internalNameToCanonicalName(String typeName) {
return typeName.replaceAll("\\$", ".");
}
private static Type objectTypeArgumentToType(SignatureAttribute.ObjectType typeArgument, TypeSolver typeSolver, TypeParametrizable typeParametrizable) {
String typeName = typeArgument.jvmTypeName();
Optional<Type> type = getGenericParameterByName(typeName, typeParametrizable);
return type.orElseGet(() -> new ReferenceTypeImpl(
typeSolver.solveType(internalNameToCanonicalName(typeName)),
typeSolver));
}
private static Optional<Type> getGenericParameterByName(String typeName, TypeParametrizable typeParametrizable) {
Optional<TypeParameterDeclaration> tp = typeParametrizable.findTypeParameter(typeName);
return tp.map(TypeVariable::new);
}
private static Type typeArgumentToType(SignatureAttribute.TypeArgument typeArgument, TypeSolver typeSolver, TypeParametrizable typeParametrizable) {
if (typeArgument.isWildcard()) {
if (typeArgument.getType() == null) {
return Wildcard.UNBOUNDED;
} else if (typeArgument.getKind() == '+') {
return Wildcard.extendsBound(objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable));
} else if (typeArgument.getKind() == '-') {
return Wildcard.superBound(objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable));
} else {
throw new UnsupportedOperationException();
}
} else {
return objectTypeArgumentToType(typeArgument.getType(), typeSolver, typeParametrizable);
}
}
}
@@ -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 Javassist.
*/
package com.github.javaparser.symbolsolver.javassistmodel;
@@ -0,0 +1,117 @@
package com.github.javaparser.symbolsolver.model.typesystem;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import java.util.Map;
import java.util.function.Function;
public class LazyType implements Type {
private Type concrete;
private Function<Void, Type> provider;
public LazyType(Function<Void, Type> provider) {
this.provider = provider;
}
private Type getType() {
if (concrete == null) {
concrete = provider.apply(null);
}
return concrete;
}
@Override
public boolean isArray() {
return getType().isArray();
}
@Override
public int arrayLevel() {
return getType().arrayLevel();
}
@Override
public boolean isPrimitive() {
return getType().isPrimitive();
}
@Override
public boolean isNull() {
return getType().isNull();
}
@Override
public boolean isReference() {
return getType().isReference();
}
@Override
public boolean isReferenceType() {
return getType().isReferenceType();
}
@Override
public boolean isVoid() {
return getType().isVoid();
}
@Override
public boolean isTypeVariable() {
return getType().isTypeVariable();
}
@Override
public boolean isWildcard() {
return getType().isArray();
}
@Override
public ArrayType asArrayType() {
return getType().asArrayType();
}
@Override
public ReferenceType asReferenceType() {
return getType().asReferenceType();
}
@Override
public TypeParameterDeclaration asTypeParameter() {
return getType().asTypeParameter();
}
@Override
public TypeVariable asTypeVariable() {
return getType().asTypeVariable();
}
@Override
public PrimitiveType asPrimitive() {
return getType().asPrimitive();
}
@Override
public Wildcard asWildcard() {
return getType().asWildcard();
}
@Override
public String describe() {
return getType().describe();
}
@Override
public Type replaceTypeVariables(TypeParameterDeclaration tp, Type replaced, Map<TypeParameterDeclaration, Type> inferredTypes) {
return getType().replaceTypeVariables(tp, replaced, inferredTypes);
}
@Override
public Type replaceTypeVariables(TypeParameterDeclaration tp, Type replaced) {
return getType().replaceTypeVariables(tp, replaced);
}
@Override
public boolean isAssignableBy(Type other) {
return getType().isAssignableBy(other);
}
}
@@ -0,0 +1,148 @@
/*
* 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.model.typesystem;
import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeVariableDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration.Bound;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
// TODO Remove references to typeSolver: it is needed to instantiate other instances of ReferenceTypeUsage
// and to get the Object type declaration
public class ReferenceTypeImpl extends ReferenceType {
public static ReferenceType undeterminedParameters(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) {
return new ReferenceTypeImpl(typeDeclaration, typeDeclaration.getTypeParameters().stream().map(
tp -> new TypeVariable(tp)
).collect(Collectors.toList()), typeSolver);
}
@Override
protected ReferenceType create(ReferenceTypeDeclaration typeDeclaration, List<Type> typeParametersCorrected, TypeSolver typeSolver) {
return new ReferenceTypeImpl(typeDeclaration, typeParametersCorrected, typeSolver);
}
@Override
protected ReferenceType create(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) {
return new ReferenceTypeImpl(typeDeclaration, typeSolver);
}
public ReferenceTypeImpl(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) {
super(typeDeclaration, typeSolver);
}
public ReferenceTypeImpl(ReferenceTypeDeclaration typeDeclaration, List<Type> typeParameters, TypeSolver typeSolver) {
super(typeDeclaration, typeParameters, typeSolver);
}
@Override
public TypeParameterDeclaration asTypeParameter() {
if (this.typeDeclaration instanceof JavaParserTypeVariableDeclaration) {
JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) this.typeDeclaration;
return javaParserTypeVariableDeclaration.asTypeParameter();
}
throw new UnsupportedOperationException(this.typeDeclaration.getClass().getCanonicalName());
}
/**
* This method checks if ThisType t = new OtherType() would compile.
*/
@Override
public boolean isAssignableBy(Type other) {
if (other instanceof NullType) {
return !this.isPrimitive();
}
// everything is assignable to Object except void
if (!other.isVoid() && this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
}
// consider boxing
if (other.isPrimitive()) {
if (this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
} else {
// Check if 'other' can be boxed to match this type
if (isCorrespondingBoxingType(other.describe())) return true;
// Resolve the boxed type and check if it can be assigned via widening reference conversion
SymbolReference<ReferenceTypeDeclaration> type = typeSolver.tryToSolveType(other.asPrimitive().getBoxTypeQName());
return type.getCorrespondingDeclaration().canBeAssignedTo(super.typeDeclaration);
}
}
if (other instanceof LambdaArgumentTypePlaceholder) {
return this.getTypeDeclaration().hasAnnotation(FunctionalInterface.class.getCanonicalName());
} else if (other instanceof ReferenceTypeImpl) {
ReferenceTypeImpl otherRef = (ReferenceTypeImpl) other;
if (compareConsideringTypeParameters(otherRef)) {
return true;
}
for (ReferenceType otherAncestor : otherRef.getAllAncestors()) {
if (compareConsideringTypeParameters(otherAncestor)) {
return true;
}
}
return false;
} else if (other.isTypeVariable()) {
for (Bound bound : other.asTypeVariable().asTypeParameter().getBounds(typeSolver)) {
if (bound.isExtends()) {
if (this.isAssignableBy(bound.getType())) {
return true;
}
}
}
return false;
} else if (other.isConstraint()){
return isAssignableBy(other.asConstraintType().getBound());
} else if (other.isWildcard()) {
if (this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
} else if (other.asWildcard().isExtends()) {
return isAssignableBy(other.asWildcard().getBoundedType());
} else {
return false;
}
} else {
return false;
}
}
@Override
public Set<MethodUsage> getDeclaredMethods() {
// TODO replace variables
Set<MethodUsage> methods = new HashSet<>();
for (MethodDeclaration methodDeclaration : getTypeDeclaration().getDeclaredMethods()) {
MethodUsage methodUsage = new MethodUsage(methodDeclaration);
methods.add(methodUsage);
}
return methods;
}
}
@@ -0,0 +1,36 @@
package com.github.javaparser.symbolsolver.reflectionmodel;
import com.github.javaparser.symbolsolver.logic.ObjectProvider;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
/**
* @author Federico Tomassetti
*/
public class MyObjectProvider implements ObjectProvider {
public static final MyObjectProvider INSTANCE = new MyObjectProvider();
private MyObjectProvider() {
// prevent instantiation
}
@Override
public ReferenceType object() {
return new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, new ReflectionTypeSolver()), new ReflectionTypeSolver());
}
@Override
public ReferenceType byName(String qualifiedName) {
TypeSolver typeSolver = new ReflectionTypeSolver();
ReferenceTypeDeclaration typeDeclaration = typeSolver.solveType(qualifiedName);
if (!typeDeclaration.getTypeParameters().isEmpty()) {
throw new UnsupportedOperationException();
}
return new ReferenceTypeImpl(typeDeclaration, typeSolver);
}
}
@@ -0,0 +1,190 @@
package com.github.javaparser.symbolsolver.reflectionmodel;
import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
import com.github.javaparser.symbolsolver.logic.FunctionalInterfaceLogic;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.typesystem.NullType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
class ReflectionClassAdapter {
private Class<?> clazz;
private TypeSolver typeSolver;
private ReferenceTypeDeclaration typeDeclaration;
public ReflectionClassAdapter(Class<?> clazz, TypeSolver typeSolver, ReferenceTypeDeclaration typeDeclaration) {
this.clazz = clazz;
this.typeSolver = typeSolver;
this.typeDeclaration = typeDeclaration;
}
public ReferenceTypeImpl getSuperClass() {
if (clazz.getGenericSuperclass() == null) {
return null;
}
java.lang.reflect.Type superType = clazz.getGenericSuperclass();
if (superType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superType;
List<Type> typeParameters = Arrays.stream(parameterizedType.getActualTypeArguments())
.map((t) -> ReflectionFactory.typeUsageFor(t, typeSolver))
.collect(Collectors.toList());
return new ReferenceTypeImpl(new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver), typeParameters, typeSolver);
}
return new ReferenceTypeImpl(new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver), typeSolver);
}
public List<ReferenceType> getInterfaces() {
List<ReferenceType> interfaces = new ArrayList<>();
for (java.lang.reflect.Type superInterface : clazz.getGenericInterfaces()) {
if (superInterface instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superInterface;
List<Type> typeParameters = Arrays.stream(parameterizedType.getActualTypeArguments())
.map((t) -> ReflectionFactory.typeUsageFor(t, typeSolver))
.collect(Collectors.toList());
interfaces.add(new ReferenceTypeImpl(new ReflectionInterfaceDeclaration((Class<?>) ((ParameterizedType) superInterface).getRawType(), typeSolver), typeParameters, typeSolver));
} else {
interfaces.add(new ReferenceTypeImpl(new ReflectionInterfaceDeclaration((Class<?>) superInterface, typeSolver), typeSolver));
}
}
return interfaces;
}
public List<ReferenceType> getAncestors() {
List<ReferenceType> ancestors = new LinkedList<>();
if (getSuperClass() != null) {
ReferenceTypeImpl superClass = getSuperClass();
ancestors.add(superClass);
} else {
ReferenceTypeImpl object = new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
ancestors.add(object);
}
ancestors.addAll(getInterfaces());
for (int i = 0; i < ancestors.size(); i++) {
ReferenceType ancestor = ancestors.get(i);
if (ancestor.hasName() && ancestor.getQualifiedName().equals(Object.class.getCanonicalName())) {
ancestors.remove(i);
i--;
}
}
return ancestors;
}
public FieldDeclaration getField(String name) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getName().equals(name)) {
return new ReflectionFieldDeclaration(field, typeSolver);
}
}
for (ReferenceType ancestor : typeDeclaration.getAllAncestors()) {
if (ancestor.getTypeDeclaration().hasField(name)) {
ReflectionFieldDeclaration reflectionFieldDeclaration = (ReflectionFieldDeclaration) ancestor.getTypeDeclaration().getField(name);
return reflectionFieldDeclaration.replaceType(ancestor.getFieldType(name).get());
}
}
throw new UnsolvedSymbolException(name, "Field in " + this);
}
public boolean hasField(String name) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getName().equals(name)) {
return true;
}
}
ReferenceTypeImpl superclass = getSuperClass();
if (superclass == null) {
return false;
} else {
return superclass.getTypeDeclaration().hasField(name);
}
}
public List<FieldDeclaration> getAllFields() {
ArrayList<FieldDeclaration> fields = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
fields.add(new ReflectionFieldDeclaration(field, typeSolver));
}
for (ReferenceType ancestor : typeDeclaration.getAllAncestors()) {
fields.addAll(ancestor.getTypeDeclaration().getAllFields());
}
return fields;
}
public Set<MethodDeclaration> getDeclaredMethods() {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(m -> !m.isSynthetic() && !m.isBridge())
.map(m -> new ReflectionMethodDeclaration(m, typeSolver))
.collect(Collectors.toSet());
}
public List<TypeParameterDeclaration> getTypeParameters() {
List<TypeParameterDeclaration> params = new ArrayList<>();
for (TypeVariable<?> tv : this.clazz.getTypeParameters()) {
params.add(new ReflectionTypeParameter(tv, true, typeSolver));
}
return params;
}
public boolean isAssignableBy(Type type) {
if (type instanceof NullType) {
return true;
}
if (type instanceof LambdaArgumentTypePlaceholder) {
return isFunctionalInterface();
}
if (type.isArray()) {
return false;
}
if (type.isPrimitive()) {
return false;
}
if (type.describe().equals(typeDeclaration.getQualifiedName())) {
return true;
}
if (type instanceof ReferenceTypeImpl) {
ReferenceTypeImpl otherTypeDeclaration = (ReferenceTypeImpl) type;
return otherTypeDeclaration.getTypeDeclaration().canBeAssignedTo(typeDeclaration);
}
return false;
}
public boolean hasDirectlyAnnotation(String canonicalName) {
for (Annotation a : clazz.getDeclaredAnnotations()) {
if (a.annotationType().getCanonicalName().equals(canonicalName)) {
return true;
}
}
return false;
}
private final boolean isFunctionalInterface() {
return FunctionalInterfaceLogic.getFunctionalMethod(typeDeclaration).isPresent();
}
public List<ConstructorDeclaration> getConstructors() {
return Arrays.stream(clazz.getConstructors())
.map(m -> new ReflectionConstructorDeclaration(m, typeSolver))
.collect(Collectors.toList());
}
public Optional<ReferenceTypeDeclaration> containerType() {
Class<?> declaringClass = clazz.getDeclaringClass();
return declaringClass == null ?
Optional.empty() :
Optional.of(ReflectionFactory.typeDeclarationFor(declaringClass, typeSolver));
}
}
@@ -0,0 +1,343 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.ast.Node;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
import com.github.javaparser.symbolsolver.javaparsermodel.contexts.ContextHelper;
import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.reflectionmodel.comparators.MethodComparator;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class ReflectionClassDeclaration extends AbstractClassDeclaration {
///
/// Fields
///
private Class<?> clazz;
private TypeSolver typeSolver;
private ReflectionClassAdapter reflectionClassAdapter;
///
/// Constructors
///
public ReflectionClassDeclaration(Class<?> clazz, TypeSolver typeSolver) {
if (clazz == null) {
throw new IllegalArgumentException("Class should not be null");
}
if (clazz.isInterface()) {
throw new IllegalArgumentException("Class should not be an interface");
}
if (clazz.isPrimitive()) {
throw new IllegalArgumentException("Class should not represent a primitive class");
}
if (clazz.isArray()) {
throw new IllegalArgumentException("Class should not be an array");
}
if (clazz.isEnum()) {
throw new IllegalArgumentException("Class should not be an enum");
}
this.clazz = clazz;
this.typeSolver = typeSolver;
this.reflectionClassAdapter = new ReflectionClassAdapter(clazz, typeSolver, this);
}
///
/// Public methods
///
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return reflectionClassAdapter.getDeclaredMethods();
}
@Override
public List<ReferenceType> getAncestors() {
return reflectionClassAdapter.getAncestors();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ReflectionClassDeclaration that = (ReflectionClassDeclaration) o;
if (!clazz.getCanonicalName().equals(that.clazz.getCanonicalName())) return false;
return true;
}
@Override
public int hashCode() {
return clazz.hashCode();
}
@Override
public String getPackageName() {
if (clazz.getPackage() != null) {
return clazz.getPackage().getName();
}
return null;
}
@Override
public String getClassName() {
String canonicalName = clazz.getCanonicalName();
if (canonicalName != null && getPackageName() != null) {
return canonicalName.substring(getPackageName().length() + 1, canonicalName.length());
}
return null;
}
@Override
public String getQualifiedName() {
return clazz.getCanonicalName();
}
@Deprecated
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> argumentsTypes, boolean staticOnly) {
List<MethodDeclaration> methods = new ArrayList<>();
Predicate<Method> staticFilter = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
for (Method method : Arrays.stream(clazz.getDeclaredMethods()).filter((m) -> m.getName().equals(name)).filter(staticFilter)
.sorted(new MethodComparator()).collect(Collectors.toList())) {
if (method.isBridge() || method.isSynthetic()) continue;
MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
methods.add(methodDeclaration);
}
if (getSuperClass() != null) {
ClassDeclaration superClass = (ClassDeclaration) getSuperClass().getTypeDeclaration();
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(superClass, name, argumentsTypes, staticOnly, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
}
}
for (ReferenceType interfaceDeclaration : getInterfaces()) {
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(interfaceDeclaration.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
}
}
return MethodResolutionLogic.findMostApplicable(methods, name, argumentsTypes, typeSolver);
}
@Override
public String toString() {
return "ReflectionClassDeclaration{" +
"clazz=" + getId() +
'}';
}
public Type getUsage(Node node) {
return new ReferenceTypeImpl(this, typeSolver);
}
public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argumentsTypes, TypeSolver typeSolver, Context invokationContext, List<Type> typeParameterValues) {
List<MethodUsage> methods = new ArrayList<>();
for (Method method : Arrays.stream(clazz.getDeclaredMethods()).filter((m) -> m.getName().equals(name)).sorted(new MethodComparator()).collect(Collectors.toList())) {
if (method.isBridge() || method.isSynthetic()) continue;
MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
MethodUsage methodUsage = new MethodUsage(methodDeclaration);
for (int i = 0; i < getTypeParameters().size() && i < typeParameterValues.size(); i++) {
TypeParameterDeclaration tpToReplace = getTypeParameters().get(i);
Type newValue = typeParameterValues.get(i);
methodUsage = methodUsage.replaceTypeParameter(tpToReplace, newValue);
}
methods.add(methodUsage);
}
if (getSuperClass() != null) {
ClassDeclaration superClass = (ClassDeclaration) getSuperClass().getTypeDeclaration();
Optional<MethodUsage> ref = ContextHelper.solveMethodAsUsage(superClass, name, argumentsTypes, typeSolver, invokationContext, typeParameterValues);
if (ref.isPresent()) {
methods.add(ref.get());
}
}
for (ReferenceType interfaceDeclaration : getInterfaces()) {
Optional<MethodUsage> ref = ContextHelper.solveMethodAsUsage(interfaceDeclaration.getTypeDeclaration(), name, argumentsTypes, typeSolver, invokationContext, typeParameterValues);
if (ref.isPresent()) {
methods.add(ref.get());
}
}
Optional<MethodUsage> ref = MethodResolutionLogic.findMostApplicableUsage(methods, name, argumentsTypes, typeSolver);
return ref;
}
@Override
public boolean canBeAssignedTo(ReferenceTypeDeclaration other) {
if (other instanceof LambdaArgumentTypePlaceholder) {
return isFunctionalInterface();
}
if (other.getQualifiedName().equals(getQualifiedName())) {
return true;
}
if (this.clazz.getSuperclass() != null
&& new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver).canBeAssignedTo(other)) {
return true;
}
for (Class<?> interfaze : clazz.getInterfaces()) {
if (new ReflectionInterfaceDeclaration(interfaze, typeSolver).canBeAssignedTo(other)) {
return true;
}
}
return false;
}
@Override
public boolean isAssignableBy(Type type) {
return reflectionClassAdapter.isAssignableBy(type);
}
@Override
public boolean isTypeParameter() {
return false;
}
@Override
public FieldDeclaration getField(String name) {
return reflectionClassAdapter.getField(name);
}
@Override
public List<FieldDeclaration> getAllFields() {
return reflectionClassAdapter.getAllFields();
}
@Deprecated
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (Field field : clazz.getFields()) {
if (field.getName().equals(name)) {
return SymbolReference.solved(new ReflectionFieldDeclaration(field, typeSolver));
}
}
return SymbolReference.unsolved(ValueDeclaration.class);
}
@Override
public boolean hasDirectlyAnnotation(String canonicalName) {
return reflectionClassAdapter.hasDirectlyAnnotation(canonicalName);
}
@Override
public boolean hasField(String name) {
return reflectionClassAdapter.hasField(name);
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration other) {
return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
}
@Override
public String getName() {
return clazz.getSimpleName();
}
@Override
public boolean isField() {
return false;
}
@Override
public boolean isParameter() {
return false;
}
@Override
public boolean isType() {
return true;
}
@Override
public boolean isClass() {
return !clazz.isInterface();
}
@Override
public ReferenceTypeImpl getSuperClass() {
return reflectionClassAdapter.getSuperClass();
}
@Override
public List<ReferenceType> getInterfaces() {
return reflectionClassAdapter.getInterfaces();
}
@Override
public boolean isInterface() {
return clazz.isInterface();
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return reflectionClassAdapter.getTypeParameters();
}
@Override
public AccessLevel accessLevel() {
return ReflectionFactory.modifiersToAccessLevel(this.clazz.getModifiers());
}
@Override
public List<ConstructorDeclaration> getConstructors() {
return reflectionClassAdapter.getConstructors();
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
return reflectionClassAdapter.containerType();
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
return Arrays.stream(this.clazz.getDeclaredClasses())
.map(ic -> ReflectionFactory.typeDeclarationFor(ic, typeSolver))
.collect(Collectors.toSet());
}
///
/// Protected methods
///
@Override
protected ReferenceType object() {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
}
@@ -0,0 +1,77 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Fred Lefévère-Laoide
*/
public class ReflectionConstructorDeclaration implements ConstructorDeclaration {
private Constructor<?> constructor;
private TypeSolver typeSolver;
public ReflectionConstructorDeclaration(Constructor<?> constructor,
TypeSolver typeSolver) {
this.constructor = constructor;
this.typeSolver = typeSolver;
}
@Override
public ClassDeclaration declaringType() {
return new ReflectionClassDeclaration(constructor.getDeclaringClass(), typeSolver);
}
@Override
public int getNumberOfParams() {
return constructor.getParameterCount();
}
@Override
public ParameterDeclaration getParam(int i) {
if (i < 0 || i >= getNumberOfParams()) {
throw new IllegalArgumentException(String.format("No param with index %d. Number of params: %d", i, getNumberOfParams()));
}
boolean variadic = false;
if (constructor.isVarArgs()) {
variadic = i == (constructor.getParameterCount() - 1);
}
return new ReflectionParameterDeclaration(constructor.getParameterTypes()[i], constructor.getGenericParameterTypes()[i], typeSolver, variadic);
}
@Override
public String getName() {
return constructor.getName();
}
@Override
public AccessLevel accessLevel() {
return ReflectionFactory.modifiersToAccessLevel(constructor.getModifiers());
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return Arrays.stream(constructor.getTypeParameters()).map((refTp) -> new ReflectionTypeParameter(refTp, false, typeSolver)).collect(Collectors.toList());
}
}
@@ -0,0 +1,191 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.logic.ConfilictingGenericTypesException;
import com.github.javaparser.symbolsolver.logic.InferenceContext;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.*;
/**
* @author Federico Tomassetti
*/
public class ReflectionEnumDeclaration extends AbstractTypeDeclaration implements EnumDeclaration {
///
/// Fields
///
private Class<?> clazz;
private TypeSolver typeSolver;
private ReflectionClassAdapter reflectionClassAdapter;
///
/// Constructors
///
public ReflectionEnumDeclaration(Class<?> clazz, TypeSolver typeSolver) {
if (clazz == null) {
throw new IllegalArgumentException("Class should not be null");
}
if (clazz.isInterface()) {
throw new IllegalArgumentException("Class should not be an interface");
}
if (clazz.isPrimitive()) {
throw new IllegalArgumentException("Class should not represent a primitive class");
}
if (clazz.isArray()) {
throw new IllegalArgumentException("Class should not be an array");
}
if (!clazz.isEnum()) {
throw new IllegalArgumentException("Class should be an enum");
}
this.clazz = clazz;
this.typeSolver = typeSolver;
this.reflectionClassAdapter = new ReflectionClassAdapter(clazz, typeSolver, this);
}
///
/// Public methods
///
@Override
public AccessLevel accessLevel() {
return ReflectionFactory.modifiersToAccessLevel(this.clazz.getModifiers());
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
return reflectionClassAdapter.containerType();
}
@Override
public String getPackageName() {
if (clazz.getPackage() != null) {
return clazz.getPackage().getName();
}
return null;
}
@Override
public String getClassName() {
String canonicalName = clazz.getCanonicalName();
if (canonicalName != null && getPackageName() != null) {
return canonicalName.substring(getPackageName().length() + 1, canonicalName.length());
}
return null;
}
@Override
public String getQualifiedName() {
return clazz.getCanonicalName();
}
@Override
public List<ReferenceType> getAncestors() {
return reflectionClassAdapter.getAncestors();
}
@Override
public FieldDeclaration getField(String name) {
return reflectionClassAdapter.getField(name);
}
@Override
public boolean hasField(String name) {
return reflectionClassAdapter.hasField(name);
}
@Override
public List<FieldDeclaration> getAllFields() {
return reflectionClassAdapter.getAllFields();
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return reflectionClassAdapter.getDeclaredMethods();
}
@Override
public boolean isAssignableBy(Type type) {
return reflectionClassAdapter.isAssignableBy(type);
}
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration other) {
return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
}
@Override
public boolean hasDirectlyAnnotation(String qualifiedName) {
return reflectionClassAdapter.hasDirectlyAnnotation(qualifiedName);
}
@Override
public String getName() {
return clazz.getSimpleName();
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return reflectionClassAdapter.getTypeParameters();
}
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> parameterTypes, boolean staticOnly) {
return ReflectionMethodResolutionLogic.solveMethod(name, parameterTypes, staticOnly,
typeSolver,this, clazz);
}
public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> parameterTypes, TypeSolver typeSolver, Context invokationContext, List<Type> typeParameterValues) {
Optional<MethodUsage> res = ReflectionMethodResolutionLogic.solveMethodAsUsage(name, parameterTypes, typeSolver, invokationContext,
typeParameterValues, this, clazz);
if (res.isPresent()) {
// We have to replace method type typeParametersValues here
InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE);
MethodUsage methodUsage = res.get();
int i = 0;
List<Type> parameters = new LinkedList<>();
for (Type actualType : parameterTypes) {
Type formalType = methodUsage.getParamType(i);
// We need to replace the class type typeParametersValues (while we derive the method ones)
parameters.add(inferenceContext.addPair(formalType, actualType));
i++;
}
try {
Type returnType = inferenceContext.addSingle(methodUsage.returnType());
for (int j=0;j<parameters.size();j++) {
methodUsage = methodUsage.replaceParamType(j, inferenceContext.resolve(parameters.get(j)));
}
methodUsage = methodUsage.replaceReturnType(inferenceContext.resolve(returnType));
return Optional.of(methodUsage);
} catch (ConfilictingGenericTypesException e) {
return Optional.empty();
}
} else {
return res;
}
}
}
@@ -0,0 +1,118 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.model.declarations.AccessLevel;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.*;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Federico Tomassetti
*/
public class ReflectionFactory {
public static ReferenceTypeDeclaration typeDeclarationFor(Class<?> clazz, TypeSolver typeSolver) {
if (clazz.isArray()) {
throw new IllegalArgumentException("No type declaration available for an Array");
} else if (clazz.isPrimitive()) {
throw new IllegalArgumentException();
} else if (clazz.isInterface()) {
return new ReflectionInterfaceDeclaration(clazz, typeSolver);
} else if (clazz.isEnum()) {
return new ReflectionEnumDeclaration(clazz, typeSolver);
} else {
return new ReflectionClassDeclaration(clazz, typeSolver);
}
}
public static Type typeUsageFor(java.lang.reflect.Type type, TypeSolver typeSolver) {
if (type instanceof java.lang.reflect.TypeVariable) {
java.lang.reflect.TypeVariable<?> tv = (java.lang.reflect.TypeVariable<?>) type;
boolean declaredOnClass = tv.getGenericDeclaration() instanceof java.lang.reflect.Type;
TypeParameterDeclaration typeParameter = new ReflectionTypeParameter(tv, declaredOnClass, typeSolver);
return new com.github.javaparser.symbolsolver.model.typesystem.TypeVariable(typeParameter);
} else if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
ReferenceType rawType = typeUsageFor(pt.getRawType(), typeSolver).asReferenceType();
List<java.lang.reflect.Type> actualTypes = new ArrayList<>();
actualTypes.addAll(Arrays.asList(pt.getActualTypeArguments()));
// we consume the actual types
rawType = rawType.transformTypeParameters(tp -> typeUsageFor(actualTypes.remove(0), typeSolver)).asReferenceType();
return rawType;
} else if (type instanceof Class) {
Class<?> c = (Class<?>) type;
if (c.isPrimitive()) {
if (c.getName().equals(Void.TYPE.getName())) {
return VoidType.INSTANCE;
} else {
return PrimitiveType.byName(c.getName());
}
} else if (c.isArray()) {
return new ArrayType(typeUsageFor(c.getComponentType(), typeSolver));
} else {
return new ReferenceTypeImpl(typeDeclarationFor(c, typeSolver), typeSolver);
}
} else if (type instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) type;
return new ArrayType(typeUsageFor(genericArrayType.getGenericComponentType(), typeSolver));
} else if (type instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) type;
if (wildcardType.getLowerBounds().length > 0 && wildcardType.getUpperBounds().length > 0) {
if (wildcardType.getUpperBounds().length == 1 && wildcardType.getUpperBounds()[0].getTypeName().equals("java.lang.Object")) {
// ok, it does not matter
}
}
if (wildcardType.getLowerBounds().length > 0) {
if (wildcardType.getLowerBounds().length > 1) {
throw new UnsupportedOperationException();
}
return Wildcard.superBound(typeUsageFor(wildcardType.getLowerBounds()[0], typeSolver));
}
if (wildcardType.getUpperBounds().length > 0) {
if (wildcardType.getUpperBounds().length > 1) {
throw new UnsupportedOperationException();
}
return Wildcard.extendsBound(typeUsageFor(wildcardType.getUpperBounds()[0], typeSolver));
}
return Wildcard.UNBOUNDED;
} else {
throw new UnsupportedOperationException(type.getClass().getCanonicalName() + " " + type);
}
}
static AccessLevel modifiersToAccessLevel(final int modifiers) {
if (Modifier.isPublic(modifiers)) {
return AccessLevel.PUBLIC;
} else if (Modifier.isProtected(modifiers)) {
return AccessLevel.PROTECTED;
} else if (Modifier.isPrivate(modifiers)) {
return AccessLevel.PRIVATE;
} else {
return AccessLevel.PACKAGE_PROTECTED;
}
}
}
@@ -0,0 +1,97 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.model.declarations.AccessLevel;
import com.github.javaparser.symbolsolver.model.declarations.FieldDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @author Federico Tomassetti
*/
public class ReflectionFieldDeclaration implements FieldDeclaration {
private Field field;
private TypeSolver typeSolver;
private Type type;
public ReflectionFieldDeclaration(Field field, TypeSolver typeSolver) {
this.field = field;
this.typeSolver = typeSolver;
this.type = calcType();
}
private ReflectionFieldDeclaration(Field field, TypeSolver typeSolver, Type type) {
this.field = field;
this.typeSolver = typeSolver;
this.type = type;
}
@Override
public Type getType() {
return type;
}
private Type calcType() {
// TODO consider interfaces, enums, primitive types, arrays
return ReflectionFactory.typeUsageFor(field.getGenericType(), typeSolver);
}
@Override
public String getName() {
return field.getName();
}
@Override
public boolean isStatic() {
return Modifier.isStatic(field.getModifiers());
}
@Override
public boolean isField() {
return true;
}
@Override
public TypeDeclaration declaringType() {
return ReflectionFactory.typeDeclarationFor(field.getDeclaringClass(), typeSolver);
}
public FieldDeclaration replaceType(Type fieldType) {
return new ReflectionFieldDeclaration(field, typeSolver, fieldType);
}
@Override
public boolean isParameter() {
return false;
}
@Override
public boolean isType() {
return false;
}
@Override
public AccessLevel accessLevel() {
return ReflectionFactory.modifiersToAccessLevel(field.getModifiers());
}
}
@@ -0,0 +1,305 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.ast.Node;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
import com.github.javaparser.symbolsolver.logic.ConfilictingGenericTypesException;
import com.github.javaparser.symbolsolver.logic.InferenceContext;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.NullType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class ReflectionInterfaceDeclaration extends AbstractTypeDeclaration implements InterfaceDeclaration {
///
/// Fields
///
private Class<?> clazz;
private TypeSolver typeSolver;
private ReflectionClassAdapter reflectionClassAdapter;
///
/// Constructor
///
public ReflectionInterfaceDeclaration(Class<?> clazz, TypeSolver typeSolver) {
if (!clazz.isInterface()) {
throw new IllegalArgumentException();
}
this.clazz = clazz;
this.typeSolver = typeSolver;
this.reflectionClassAdapter = new ReflectionClassAdapter(clazz, typeSolver, this);
}
///
/// Public methods
///
@Override
public boolean isAssignableBy(ReferenceTypeDeclaration other) {
return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
}
@Override
public String getPackageName() {
if (clazz.getPackage() != null) {
return clazz.getPackage().getName();
}
return null;
}
@Override
public String getClassName() {
String canonicalName = clazz.getCanonicalName();
if (canonicalName != null && getPackageName() != null) {
return canonicalName.substring(getPackageName().length() + 1, canonicalName.length());
}
return null;
}
@Override
public String getQualifiedName() {
return clazz.getCanonicalName();
}
@Deprecated
public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> parameterTypes, boolean staticOnly) {
return ReflectionMethodResolutionLogic.solveMethod(name, parameterTypes, staticOnly,
typeSolver,this, clazz);
}
@Override
public String toString() {
return "ReflectionInterfaceDeclaration{" +
"clazz=" + clazz.getCanonicalName() +
'}';
}
public Type getUsage(Node node) {
return new ReferenceTypeImpl(this, typeSolver);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ReflectionInterfaceDeclaration)) return false;
ReflectionInterfaceDeclaration that = (ReflectionInterfaceDeclaration) o;
if (!clazz.getCanonicalName().equals(that.clazz.getCanonicalName())) return false;
if (!getTypeParameters().equals(that.getTypeParameters())) {
return false;
}
return true;
}
@Override
public int hashCode() {
return clazz.hashCode();
}
public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> parameterTypes, TypeSolver typeSolver, Context invokationContext, List<Type> typeParameterValues) {
Optional<MethodUsage> res = ReflectionMethodResolutionLogic.solveMethodAsUsage(name, parameterTypes, typeSolver, invokationContext,
typeParameterValues, this, clazz);
if (res.isPresent()) {
// We have to replace method type typeParametersValues here
InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE);
MethodUsage methodUsage = res.get();
int i = 0;
List<Type> parameters = new LinkedList<>();
for (Type actualType : parameterTypes) {
Type formalType = methodUsage.getParamType(i);
// We need to replace the class type typeParametersValues (while we derive the method ones)
parameters.add(inferenceContext.addPair(formalType, actualType));
i++;
}
try {
Type returnType = inferenceContext.addSingle(methodUsage.returnType());
for (int j=0;j<parameters.size();j++) {
methodUsage = methodUsage.replaceParamType(j, inferenceContext.resolve(parameters.get(j)));
}
methodUsage = methodUsage.replaceReturnType(inferenceContext.resolve(returnType));
return Optional.of(methodUsage);
} catch (ConfilictingGenericTypesException e) {
return Optional.empty();
}
} else {
return res;
}
}
@Override
public boolean canBeAssignedTo(ReferenceTypeDeclaration other) {
if (other instanceof LambdaArgumentTypePlaceholder) {
return isFunctionalInterface();
}
if (other.getQualifiedName().equals(getQualifiedName())) {
return true;
}
if (this.clazz.getSuperclass() != null
&& new ReflectionInterfaceDeclaration(clazz.getSuperclass(), typeSolver).canBeAssignedTo(other)) {
return true;
}
for (Class interfaze : clazz.getInterfaces()) {
if (new ReflectionInterfaceDeclaration(interfaze, typeSolver).canBeAssignedTo(other)) {
return true;
}
}
if (other.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
}
return false;
}
@Override
public boolean isAssignableBy(Type type) {
if (type instanceof NullType) {
return true;
}
if (type instanceof LambdaArgumentTypePlaceholder) {
return isFunctionalInterface();
}
if (type.isArray()) {
return false;
}
if (type.isPrimitive()) {
return false;
}
if (type.describe().equals(getQualifiedName())) {
return true;
}
if (type instanceof ReferenceTypeImpl) {
ReferenceTypeImpl otherTypeDeclaration = (ReferenceTypeImpl) type;
return otherTypeDeclaration.getTypeDeclaration().canBeAssignedTo(this);
}
return false;
}
@Override
public boolean isTypeParameter() {
return false;
}
@Override
public FieldDeclaration getField(String name) {
return reflectionClassAdapter.getField(name);
}
@Override
public List<FieldDeclaration> getAllFields() {
return reflectionClassAdapter.getAllFields();
}
@Deprecated
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
for (Field field : clazz.getFields()) {
if (field.getName().equals(name)) {
return SymbolReference.solved(new ReflectionFieldDeclaration(field, typeSolver));
}
}
return SymbolReference.unsolved(ValueDeclaration.class);
}
@Override
public List<ReferenceType> getAncestors() {
return reflectionClassAdapter.getAncestors();
}
@Override
public Set<MethodDeclaration> getDeclaredMethods() {
return reflectionClassAdapter.getDeclaredMethods();
}
@Override
public boolean hasField(String name) {
return reflectionClassAdapter.hasField(name);
}
@Override
public String getName() {
return clazz.getSimpleName();
}
@Override
public boolean isInterface() {
return true;
}
@Override
public List<ReferenceType> getInterfacesExtended() {
List<ReferenceType> res = new ArrayList<>();
for (Class i : clazz.getInterfaces()) {
res.add(new ReferenceTypeImpl(new ReflectionInterfaceDeclaration(i, typeSolver), typeSolver));
}
return res;
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
return reflectionClassAdapter.containerType();
}
@Override
public Set<ReferenceTypeDeclaration> internalTypes() {
return Arrays.stream(this.clazz.getDeclaredClasses())
.map(ic -> ReflectionFactory.typeDeclarationFor(ic, typeSolver))
.collect(Collectors.toSet());
}
@Override
public InterfaceDeclaration asInterface() {
return this;
}
@Override
public boolean hasDirectlyAnnotation(String canonicalName) {
return reflectionClassAdapter.hasDirectlyAnnotation(canonicalName);
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return reflectionClassAdapter.getTypeParameters();
}
@Override
public AccessLevel accessLevel() {
return ReflectionFactory.modifiersToAccessLevel(this.clazz.getModifiers());
}
}
@@ -0,0 +1,135 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.declarations.common.MethodDeclarationCommonLogic;
import com.github.javaparser.symbolsolver.model.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class ReflectionMethodDeclaration implements MethodDeclaration {
private Method method;
private TypeSolver typeSolver;
public ReflectionMethodDeclaration(Method method, TypeSolver typeSolver) {
this.method = method;
if (method.isSynthetic() || method.isBridge()) {
throw new IllegalArgumentException();
}
this.typeSolver = typeSolver;
}
@Override
public String getName() {
return method.getName();
}
@Override
public boolean isField() {
return false;
}
@Override
public boolean isParameter() {
return false;
}
@Override
public String toString() {
return "ReflectionMethodDeclaration{" +
"method=" + method +
'}';
}
@Override
public boolean isType() {
return false;
}
@Override
public ReferenceTypeDeclaration declaringType() {
if (method.getDeclaringClass().isInterface()) {
return new ReflectionInterfaceDeclaration(method.getDeclaringClass(), typeSolver);
}
if (method.getDeclaringClass().isEnum()) {
return new ReflectionEnumDeclaration(method.getDeclaringClass(), typeSolver);
} else {
return new ReflectionClassDeclaration(method.getDeclaringClass(), typeSolver);
}
}
@Override
public Type getReturnType() {
return ReflectionFactory.typeUsageFor(method.getGenericReturnType(), typeSolver);
}
@Override
public int getNumberOfParams() {
return method.getParameterTypes().length;
}
@Override
public ParameterDeclaration getParam(int i) {
boolean variadic = false;
if (method.isVarArgs()) {
variadic = i == (method.getParameterCount() - 1);
}
return new ReflectionParameterDeclaration(method.getParameterTypes()[i], method.getGenericParameterTypes()[i], typeSolver, variadic);
}
@Override
public List<TypeParameterDeclaration> getTypeParameters() {
return Arrays.stream(method.getTypeParameters()).map((refTp) -> new ReflectionTypeParameter(refTp, false, typeSolver)).collect(Collectors.toList());
}
public MethodUsage resolveTypeVariables(Context context, List<Type> parameterTypes) {
return new MethodDeclarationCommonLogic(this, typeSolver).resolveTypeVariables(context, parameterTypes);
}
@Override
public boolean isAbstract() {
return Modifier.isAbstract(method.getModifiers());
}
@Override
public boolean isDefaultMethod() {
return method.isDefault();
}
@Override
public boolean isStatic() {
return Modifier.isStatic(method.getModifiers());
}
@Override
public AccessLevel accessLevel() {
return ReflectionFactory.modifiersToAccessLevel(this.method.getModifiers());
}
}
@@ -0,0 +1,144 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
class ReflectionMethodResolutionLogic {
static SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> parameterTypes, boolean staticOnly,
TypeSolver typeSolver, ReferenceTypeDeclaration scopeType,
Class clazz){
List<MethodDeclaration> methods = new ArrayList<>();
Predicate<Method> staticOnlyCheck = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
for (Method method : clazz.getMethods()) {
if (method.isBridge() || method.isSynthetic() || !method.getName().equals(name)|| !staticOnlyCheck.test(method)) continue;
MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
methods.add(methodDeclaration);
}
for (ReferenceType ancestor : scopeType.getAncestors()) {
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(ancestor.getTypeDeclaration(), name, parameterTypes, staticOnly, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
}
}
if (scopeType.getAncestors().isEmpty()){
ReferenceTypeImpl objectClass = new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(objectClass.getTypeDeclaration(), name, parameterTypes, staticOnly, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
}
}
return MethodResolutionLogic.findMostApplicable(methods, name, parameterTypes, typeSolver);
}
static Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argumentsTypes, TypeSolver typeSolver,
Context invokationContext, List<Type> typeParameterValues,
ReferenceTypeDeclaration scopeType, Class clazz) {
if (typeParameterValues.size() != scopeType.getTypeParameters().size()) {
// if it is zero we are going to ignore them
if (!scopeType.getTypeParameters().isEmpty()) {
// Parameters not specified, so default to Object
typeParameterValues = new ArrayList<>();
for (int i = 0; i < scopeType.getTypeParameters().size(); i++) {
typeParameterValues.add(new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver));
}
}
}
List<MethodUsage> methods = new ArrayList<>();
for (Method method : clazz.getMethods()) {
if (method.getName().equals(name) && !method.isBridge() && !method.isSynthetic()) {
MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
MethodUsage methodUsage = replaceParams(typeParameterValues, scopeType, methodDeclaration);
methods.add(methodUsage);
}
}
for(ReferenceType ancestor : scopeType.getAncestors()){
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, typeSolver);
if (ref.isSolved()){
MethodDeclaration correspondingDeclaration = ref.getCorrespondingDeclaration();
MethodUsage methodUsage = replaceParams(typeParameterValues, ancestor.getTypeDeclaration(), correspondingDeclaration);
methods.add(methodUsage);
}
}
if (scopeType.getAncestors().isEmpty()){
ReferenceTypeImpl objectClass = new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(objectClass.getTypeDeclaration(), name, argumentsTypes, typeSolver);
if (ref.isSolved()) {
MethodUsage usage = replaceParams(typeParameterValues, objectClass.getTypeDeclaration(), ref.getCorrespondingDeclaration());
methods.add(usage);
}
}
final List<Type> finalTypeParameterValues = typeParameterValues;
argumentsTypes = argumentsTypes.stream().map((pt) -> {
int i = 0;
for (TypeParameterDeclaration tp : scopeType.getTypeParameters()) {
pt = pt.replaceTypeVariables(tp, finalTypeParameterValues.get(i));
i++;
}
return pt;
}).collect(Collectors.toList());
return MethodResolutionLogic.findMostApplicableUsage(methods, name, argumentsTypes, typeSolver);
}
private static MethodUsage replaceParams(List<Type> typeParameterValues, ReferenceTypeDeclaration typeParametrizable, MethodDeclaration methodDeclaration) {
MethodUsage methodUsage = new MethodUsage(methodDeclaration);
int i = 0;
// Only replace if we have enough values provided
if (typeParameterValues.size() == typeParametrizable.getTypeParameters().size()){
for (TypeParameterDeclaration tp : typeParametrizable.getTypeParameters()) {
methodUsage = methodUsage.replaceTypeParameter(tp, typeParameterValues.get(i));
i++;
}
}
for (TypeParameterDeclaration methodTypeParameter : methodDeclaration.getTypeParameters()) {
methodUsage = methodUsage.replaceTypeParameter(methodTypeParameter, new TypeVariable(methodTypeParameter));
}
return methodUsage;
}
}
@@ -0,0 +1,75 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.model.declarations.ParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
/**
* @author Federico Tomassetti
*/
public class ReflectionParameterDeclaration implements ParameterDeclaration {
private Class<?> type;
private java.lang.reflect.Type genericType;
private TypeSolver typeSolver;
private boolean variadic;
public ReflectionParameterDeclaration(Class<?> type, java.lang.reflect.Type genericType, TypeSolver typeSolver, boolean variadic) {
this.type = type;
this.genericType = genericType;
this.typeSolver = typeSolver;
this.variadic = variadic;
}
@Override
public String getName() {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return "ReflectionParameterDeclaration{" +
"type=" + type +
'}';
}
@Override
public boolean isField() {
return false;
}
@Override
public boolean isParameter() {
return true;
}
@Override
public boolean isVariadic() {
return variadic;
}
@Override
public boolean isType() {
return false;
}
@Override
public Type getType() {
return ReflectionFactory.typeUsageFor(genericType, typeSolver);
}
}
@@ -0,0 +1,130 @@
/*
* 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.reflectionmodel;
import com.github.javaparser.symbolsolver.model.declarations.MethodLikeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParametrizable;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class ReflectionTypeParameter implements TypeParameterDeclaration {
private TypeVariable typeVariable;
private TypeSolver typeSolver;
private TypeParametrizable container;
public ReflectionTypeParameter(TypeVariable typeVariable, boolean declaredOnClass, TypeSolver typeSolver) {
GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
if (genericDeclaration instanceof Class) {
container = ReflectionFactory.typeDeclarationFor((Class) genericDeclaration, typeSolver);
} else if (genericDeclaration instanceof Method) {
container = new ReflectionMethodDeclaration((Method) genericDeclaration, typeSolver);
} else if (genericDeclaration instanceof Constructor) {
container = new ReflectionConstructorDeclaration((Constructor) genericDeclaration, typeSolver);
}
this.typeVariable = typeVariable;
this.typeSolver = typeSolver;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TypeParameterDeclaration)) return false;
TypeParameterDeclaration that = (TypeParameterDeclaration) o;
if (!getQualifiedName().equals(that.getQualifiedName())) {
return false;
}
if (declaredOnType() != that.declaredOnType()) {
return false;
}
if (declaredOnMethod() != that.declaredOnMethod()) {
return false;
}
// TODO check bounds
return true;
}
@Override
public int hashCode() {
int result = typeVariable.hashCode();
result = 31 * result + container.hashCode();
return result;
}
@Override
public String getName() {
return typeVariable.getName();
}
@Override
public String getContainerQualifiedName() {
if (container instanceof ReferenceTypeDeclaration) {
return ((ReferenceTypeDeclaration) container).getQualifiedName();
} else {
return ((MethodLikeDeclaration) container).getQualifiedSignature();
}
}
@Override
public String getContainerId() {
if (container instanceof ReferenceTypeDeclaration) {
return ((ReferenceTypeDeclaration) container).getId();
} else {
return ((MethodLikeDeclaration) container).getQualifiedSignature();
}
}
@Override
public TypeParametrizable getContainer() {
return this.container;
}
@Override
public List<Bound> getBounds(TypeSolver typeSolver) {
return Arrays.stream(typeVariable.getBounds()).map((refB) -> Bound.extendsBound(ReflectionFactory.typeUsageFor(refB, typeSolver))).collect(Collectors.toList());
}
@Override
public String toString() {
return "ReflectionTypeParameter{" +
"typeVariable=" + typeVariable +
'}';
}
@Override
public Optional<ReferenceTypeDeclaration> containerType() {
if (container instanceof ReferenceTypeDeclaration) {
return Optional.of((ReferenceTypeDeclaration) container);
}
return Optional.empty();
}
}
@@ -0,0 +1,25 @@
package com.github.javaparser.symbolsolver.reflectionmodel.comparators;
import java.util.Comparator;
/**
* @author Federico Tomassetti
*/
public class ClassComparator implements Comparator<Class<?>> {
@Override
public int compare(Class<?> o1, Class<?> o2) {
int subCompare;
subCompare = o1.getCanonicalName().compareTo(o2.getCanonicalName());
if (subCompare != 0) return subCompare;
subCompare = Boolean.compare(o1.isAnnotation(), o2.isAnnotation());
if (subCompare != 0) return subCompare;
subCompare = Boolean.compare(o1.isArray(), o2.isArray());
if (subCompare != 0) return subCompare;
subCompare = Boolean.compare(o1.isEnum(), o2.isEnum());
if (subCompare != 0) return subCompare;
subCompare = Boolean.compare(o1.isInterface(), o2.isInterface());
if (subCompare != 0) return subCompare;
return 0;
}
}
@@ -0,0 +1,25 @@
package com.github.javaparser.symbolsolver.reflectionmodel.comparators;
import java.lang.reflect.Method;
import java.util.Comparator;
/**
* @author Federico Tomassetti
*/
public class MethodComparator implements Comparator<Method> {
@Override
public int compare(Method o1, Method o2) {
int compareName = o1.getName().compareTo(o2.getName());
if (compareName != 0) return compareName;
int compareNParams = o1.getParameterCount() - o2.getParameterCount();
if (compareNParams != 0) return compareNParams;
for (int i = 0; i < o1.getParameterCount(); i++) {
int compareParam = new ParameterComparator().compare(o1.getParameters()[i], o2.getParameters()[i]);
if (compareParam != 0) return compareParam;
}
int compareResult = new ClassComparator().compare(o1.getReturnType(), o2.getReturnType());
if (compareResult != 0) return compareResult;
return 0;
}
}
@@ -0,0 +1,19 @@
package com.github.javaparser.symbolsolver.reflectionmodel.comparators;
import java.lang.reflect.Parameter;
import java.util.Comparator;
/**
* @author Federico Tomassetti
*/
public class ParameterComparator implements Comparator<Parameter> {
@Override
public int compare(Parameter o1, Parameter o2) {
int compareName = o1.getName().compareTo(o2.getName());
if (compareName != 0) return compareName;
int compareType = new ClassComparator().compare(o1.getType(), o2.getType());
if (compareType != 0) return compareType;
return 0;
}
}
@@ -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 reflection.
*/
package com.github.javaparser.symbolsolver.reflectionmodel;
@@ -0,0 +1,226 @@
/*
* 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.resolution;
import com.github.javaparser.symbolsolver.model.declarations.ConstructorDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodAmbiguityException;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.ArrayType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Fred Lefévère-Laoide
*/
public class ConstructorResolutionLogic {
private static List<Type> groupVariadicParamValues(List<Type> argumentsTypes, int startVariadic,
Type variadicType) {
List<Type> res = new ArrayList<>(argumentsTypes.subList(0, startVariadic));
List<Type> variadicValues = argumentsTypes.subList(startVariadic, argumentsTypes.size());
if (variadicValues.isEmpty()) {
// TODO if there are no variadic values we should default to the bound of the formal type
res.add(variadicType);
} else {
Type componentType = findCommonType(variadicValues);
res.add(new ArrayType(componentType));
}
return res;
}
private static Type findCommonType(List<Type> variadicValues) {
if (variadicValues.isEmpty()) {
throw new IllegalArgumentException();
}
// TODO implement this decently
return variadicValues.get(0);
}
public static boolean isApplicable(ConstructorDeclaration constructor, List<Type> argumentsTypes,
TypeSolver typeSolver) {
return isApplicable(constructor, argumentsTypes, typeSolver, false);
}
private static boolean isApplicable(ConstructorDeclaration constructor, List<Type> argumentsTypes,
TypeSolver typeSolver, boolean withWildcardTolerance) {
if (constructor.hasVariadicParameter()) {
int pos = constructor.getNumberOfParams() - 1;
if (constructor.getNumberOfParams() == argumentsTypes.size()) {
// check if the last value is directly assignable as an array
Type expectedType = constructor.getLastParam().getType();
Type actualType = argumentsTypes.get(pos);
if (!expectedType.isAssignableBy(actualType)) {
for (TypeParameterDeclaration tp : constructor.getTypeParameters()) {
expectedType = MethodResolutionLogic.replaceTypeParam(expectedType, tp, typeSolver);
}
if (!expectedType.isAssignableBy(actualType)) {
if (actualType.isArray()
&& expectedType.isAssignableBy(actualType.asArrayType().getComponentType())) {
argumentsTypes.set(pos, actualType.asArrayType().getComponentType());
} else {
argumentsTypes = groupVariadicParamValues(argumentsTypes, pos,
constructor.getLastParam().getType());
}
}
} // else it is already assignable, nothing to do
} else {
if (pos > argumentsTypes.size()) {
return false;
}
argumentsTypes =
groupVariadicParamValues(argumentsTypes, pos, constructor.getLastParam().getType());
}
}
if (constructor.getNumberOfParams() != argumentsTypes.size()) {
return false;
}
Map<String, Type> matchedParameters = new HashMap<>();
boolean needForWildCardTolerance = false;
for (int i = 0; i < constructor.getNumberOfParams(); i++) {
Type expectedType = constructor.getParam(i).getType();
Type actualType = argumentsTypes.get(i);
if ((expectedType.isTypeVariable() && !(expectedType.isWildcard()))
&& expectedType.asTypeParameter().declaredOnMethod()) {
matchedParameters.put(expectedType.asTypeParameter().getName(), actualType);
continue;
}
boolean isAssignableWithoutSubstitution =
expectedType.isAssignableBy(actualType) || (constructor.getParam(i).isVariadic()
&& new ArrayType(expectedType).isAssignableBy(actualType));
if (!isAssignableWithoutSubstitution && expectedType.isReferenceType()
&& actualType.isReferenceType()) {
isAssignableWithoutSubstitution = MethodResolutionLogic.isAssignableMatchTypeParameters(
expectedType.asReferenceType(), actualType.asReferenceType(), matchedParameters);
}
if (!isAssignableWithoutSubstitution) {
List<TypeParameterDeclaration> typeParameters = constructor.getTypeParameters();
typeParameters.addAll(constructor.declaringType().getTypeParameters());
for (TypeParameterDeclaration tp : typeParameters) {
expectedType = MethodResolutionLogic.replaceTypeParam(expectedType, tp, typeSolver);
}
if (!expectedType.isAssignableBy(actualType)) {
if (actualType.isWildcard() && withWildcardTolerance && !expectedType.isPrimitive()) {
needForWildCardTolerance = true;
continue;
}
if (constructor.hasVariadicParameter() && i == constructor.getNumberOfParams() - 1) {
if (new ArrayType(expectedType).isAssignableBy(actualType)) {
continue;
}
}
return false;
}
}
}
return !withWildcardTolerance || needForWildCardTolerance;
}
/**
* @param methods we expect the methods to be ordered such that inherited methods are later in the list
* @param name
* @param argumentsTypes
* @param typeSolver
* @return
*/
public static SymbolReference<ConstructorDeclaration> findMostApplicable(
List<ConstructorDeclaration> constructors, List<Type> argumentsTypes, TypeSolver typeSolver) {
SymbolReference<ConstructorDeclaration> res =
findMostApplicable(constructors, argumentsTypes, typeSolver, false);
if (res.isSolved()) {
return res;
}
return findMostApplicable(constructors, argumentsTypes, typeSolver, true);
}
public static SymbolReference<ConstructorDeclaration> findMostApplicable(List<ConstructorDeclaration> constructors, List<Type> argumentsTypes, TypeSolver typeSolver, boolean wildcardTolerance) {
List<ConstructorDeclaration> applicableConstructors = constructors.stream().filter((m) -> isApplicable(m, argumentsTypes, typeSolver, wildcardTolerance)).collect(Collectors.toList());
if (applicableConstructors.isEmpty()) {
return SymbolReference.unsolved(ConstructorDeclaration.class);
}
if (applicableConstructors.size() == 1) {
return SymbolReference.solved(applicableConstructors.get(0));
} else {
ConstructorDeclaration winningCandidate = applicableConstructors.get(0);
ConstructorDeclaration other = null;
boolean possibleAmbiguity = false;
for (int i = 1; i < applicableConstructors.size(); i++) {
other = applicableConstructors.get(i);
if (isMoreSpecific(winningCandidate, other, typeSolver)) {
possibleAmbiguity = false;
} else if (isMoreSpecific(other, winningCandidate, typeSolver)) {
possibleAmbiguity = false;
winningCandidate = other;
} else {
if (winningCandidate.declaringType().getQualifiedName()
.equals(other.declaringType().getQualifiedName())) {
possibleAmbiguity = true;
} else {
// we expect the methods to be ordered such that inherited methods are later in the list
}
}
}
if (possibleAmbiguity) {
// pick the first exact match if it exists
if (!MethodResolutionLogic.isExactMatch(winningCandidate, argumentsTypes)) {
if (MethodResolutionLogic.isExactMatch(other, argumentsTypes)) {
winningCandidate = other;
} else {
throw new MethodAmbiguityException("Ambiguous constructor call: cannot find a most applicable constructor: " + winningCandidate + ", " + other);
}
}
}
return SymbolReference.solved(winningCandidate);
}
}
private static boolean isMoreSpecific(ConstructorDeclaration constructorA,
ConstructorDeclaration constructorB, TypeSolver typeSolver) {
boolean oneMoreSpecificFound = false;
if (constructorA.getNumberOfParams() < constructorB.getNumberOfParams()) {
return true;
}
if (constructorA.getNumberOfParams() > constructorB.getNumberOfParams()) {
return false;
}
for (int i = 0; i < constructorA.getNumberOfParams(); i++) {
Type tdA = constructorA.getParam(i).getType();
Type tdB = constructorB.getParam(i).getType();
// B is more specific
if (tdB.isAssignableBy(tdA) && !tdA.isAssignableBy(tdB)) {
oneMoreSpecificFound = true;
}
// A is more specific
if (tdA.isAssignableBy(tdB) && !tdB.isAssignableBy(tdA)) {
return false;
}
// if it matches a variadic and a not variadic I pick the not variadic
// FIXME
if (i == (constructorA.getNumberOfParams() - 1) && tdA.arrayLevel() > tdB.arrayLevel()) {
return true;
}
}
return oneMoreSpecificFound;
}
}
@@ -0,0 +1,679 @@
/*
* 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.resolution;
import com.github.javaparser.symbolsolver.core.resolution.Context;
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.JavaParserMethodDeclaration;
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.declarations.*;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
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.reflectionmodel.ReflectionEnumDeclaration;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionInterfaceDeclaration;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class MethodResolutionLogic {
private static List<Type> groupVariadicParamValues(List<Type> argumentsTypes, int startVariadic, Type variadicType) {
List<Type> res = new ArrayList<>(argumentsTypes.subList(0, startVariadic));
List<Type> variadicValues = argumentsTypes.subList(startVariadic, argumentsTypes.size());
if (variadicValues.isEmpty()) {
// TODO if there are no variadic values we should default to the bound of the formal type
res.add(variadicType);
} else {
Type componentType = findCommonType(variadicValues);
res.add(new ArrayType(componentType));
}
return res;
}
private static Type findCommonType(List<Type> variadicValues) {
if (variadicValues.isEmpty()) {
throw new IllegalArgumentException();
}
// TODO implement this decently
return variadicValues.get(0);
}
public static boolean isApplicable(MethodDeclaration method, String name, List<Type> argumentsTypes, TypeSolver typeSolver) {
return isApplicable(method, name, argumentsTypes, typeSolver, false);
}
private static boolean isApplicable(MethodDeclaration method, String name, List<Type> argumentsTypes, TypeSolver typeSolver, boolean withWildcardTolerance) {
if (!method.getName().equals(name)) {
return false;
}
if (method.hasVariadicParameter()) {
int pos = method.getNumberOfParams() - 1;
if (method.getNumberOfParams() == argumentsTypes.size()) {
// check if the last value is directly assignable as an array
Type expectedType = method.getLastParam().getType();
Type actualType = argumentsTypes.get(pos);
if (!expectedType.isAssignableBy(actualType)) {
for (TypeParameterDeclaration tp : method.getTypeParameters()) {
expectedType = replaceTypeParam(expectedType, tp, typeSolver);
}
if (!expectedType.isAssignableBy(actualType)) {
if (actualType.isArray() && expectedType.isAssignableBy(actualType.asArrayType().getComponentType())) {
argumentsTypes.set(pos, actualType.asArrayType().getComponentType());
} else {
argumentsTypes = groupVariadicParamValues(argumentsTypes, pos, method.getLastParam().getType());
}
}
} // else it is already assignable, nothing to do
} else {
if (pos > argumentsTypes.size()) {
return false;
}
argumentsTypes = groupVariadicParamValues(argumentsTypes, pos, method.getLastParam().getType());
}
}
if (method.getNumberOfParams() != argumentsTypes.size()) {
return false;
}
Map<String, Type> matchedParameters = new HashMap<>();
boolean needForWildCardTolerance = false;
for (int i = 0; i < method.getNumberOfParams(); i++) {
Type expectedType = method.getParam(i).getType();
Type actualType = argumentsTypes.get(i);
if ((expectedType.isTypeVariable() && !(expectedType.isWildcard())) && expectedType.asTypeParameter().declaredOnMethod()) {
matchedParameters.put(expectedType.asTypeParameter().getName(), actualType);
continue;
}
boolean isAssignableWithoutSubstitution = expectedType.isAssignableBy(actualType) ||
(method.getParam(i).isVariadic() && new ArrayType(expectedType).isAssignableBy(actualType));
if (!isAssignableWithoutSubstitution && expectedType.isReferenceType() && actualType.isReferenceType()) {
isAssignableWithoutSubstitution = isAssignableMatchTypeParameters(
expectedType.asReferenceType(),
actualType.asReferenceType(),
matchedParameters);
}
if (!isAssignableWithoutSubstitution) {
List<TypeParameterDeclaration> typeParameters = method.getTypeParameters();
typeParameters.addAll(method.declaringType().getTypeParameters());
for (TypeParameterDeclaration tp : typeParameters) {
expectedType = replaceTypeParam(expectedType, tp, typeSolver);
}
if (!expectedType.isAssignableBy(actualType)) {
if (actualType.isWildcard() && withWildcardTolerance && !expectedType.isPrimitive()) {
needForWildCardTolerance = true;
continue;
}
if (method.hasVariadicParameter() && i == method.getNumberOfParams() - 1) {
if (new ArrayType(expectedType).isAssignableBy(actualType)) {
continue;
}
}
return false;
}
}
}
return !withWildcardTolerance || needForWildCardTolerance;
}
public static boolean isAssignableMatchTypeParameters(Type expected, Type actual,
Map<String, Type> matchedParameters) {
if (expected.isReferenceType() && actual.isReferenceType()) {
return isAssignableMatchTypeParameters(expected.asReferenceType(), actual.asReferenceType(), matchedParameters);
} else if (expected.isTypeVariable()) {
matchedParameters.put(expected.asTypeParameter().getName(), actual);
return true;
} else {
throw new UnsupportedOperationException(expected.getClass().getCanonicalName() + " " + actual.getClass().getCanonicalName());
}
}
public static boolean isAssignableMatchTypeParameters(ReferenceType expected, ReferenceType actual,
Map<String, Type> matchedParameters) {
if (actual.getQualifiedName().equals(expected.getQualifiedName())) {
return isAssignableMatchTypeParametersMatchingQName(expected, actual, matchedParameters);
} else {
List<ReferenceType> ancestors = actual.getAllAncestors();
for (ReferenceType ancestor : ancestors) {
if (isAssignableMatchTypeParametersMatchingQName(expected, ancestor, matchedParameters)) {
return true;
}
}
}
return false;
}
private static boolean isAssignableMatchTypeParametersMatchingQName(ReferenceType expected, ReferenceType actual,
Map<String, Type> matchedParameters) {
if (!expected.getQualifiedName().equals(actual.getQualifiedName())) {
return false;
}
if (expected.typeParametersValues().size() != actual.typeParametersValues().size()) {
throw new UnsupportedOperationException();
//return true;
}
for (int i = 0; i < expected.typeParametersValues().size(); i++) {
Type expectedParam = expected.typeParametersValues().get(i);
Type actualParam = actual.typeParametersValues().get(i);
// In the case of nested parameterizations eg. List<R> <-> List<Integer>
// we should peel off one layer and ensure R <-> Integer
if (expectedParam.isReferenceType() && actualParam.isReferenceType()){
ReferenceType r1 = expectedParam.asReferenceType();
ReferenceType r2 = actualParam.asReferenceType();
return isAssignableMatchTypeParametersMatchingQName(r1, r2, matchedParameters);
}
if (expectedParam.isTypeVariable()) {
String expectedParamName = expectedParam.asTypeParameter().getName();
if (!actualParam.isTypeVariable() || !actualParam.asTypeParameter().getName().equals(expectedParamName)) {
if (matchedParameters.containsKey(expectedParamName)) {
Type matchedParameter = matchedParameters.get(expectedParamName);
if (matchedParameter.isAssignableBy(actualParam)) {
return true;
} else if (actualParam.isAssignableBy(matchedParameter)) {
matchedParameters.put(expectedParamName, actualParam);
return true;
}
return false;
} else {
matchedParameters.put(expectedParamName, actualParam);
}
}
} else if (expectedParam.isReferenceType()) {
if (!expectedParam.equals(actualParam)) {
return false;
}
} else if (expectedParam.isWildcard()) {
if (expectedParam.asWildcard().isExtends()) {
return isAssignableMatchTypeParameters(expectedParam.asWildcard().getBoundedType(), actual, matchedParameters);
}
// TODO verify super bound
return true;
} else {
throw new UnsupportedOperationException(expectedParam.describe());
}
}
return true;
}
public static Type replaceTypeParam(Type type, TypeParameterDeclaration tp, TypeSolver typeSolver) {
if (type.isTypeVariable()) {
if (type.describe().equals(tp.getName())) {
List<TypeParameterDeclaration.Bound> bounds = tp.getBounds(typeSolver);
if (bounds.size() > 1) {
throw new UnsupportedOperationException();
} else if (bounds.size() == 1) {
return bounds.get(0).getType();
} else {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
}
return type;
} else if (type.isPrimitive()) {
return type;
} else if (type.isArray()) {
return new ArrayType(replaceTypeParam(type.asArrayType().getComponentType(), tp, typeSolver));
} else if (type.isReferenceType()) {
ReferenceType result = type.asReferenceType();
result = result.transformTypeParameters(typeParam -> replaceTypeParam(typeParam, tp, typeSolver)).asReferenceType();
return result;
} else if (type.isWildcard()) {
if (type.describe().equals(tp.getName())) {
List<TypeParameterDeclaration.Bound> bounds = tp.getBounds(typeSolver);
if (bounds.size() > 1) {
throw new UnsupportedOperationException();
} else if (bounds.size() == 1) {
return bounds.get(0).getType();
} else {
return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
}
}
return type;
} else {
throw new UnsupportedOperationException("Replacing " + type + ", param " + tp + " with " + type.getClass().getCanonicalName());
}
}
public static boolean isApplicable(MethodUsage method, String name, List<Type> argumentsTypes, TypeSolver typeSolver) {
if (!method.getName().equals(name)) {
return false;
}
// TODO Consider varargs
if (method.getNoParams() != argumentsTypes.size()) {
return false;
}
for (int i = 0; i < method.getNoParams(); i++) {
Type expectedType = method.getParamType(i);
Type expectedTypeWithoutSubstitutions = expectedType;
Type expectedTypeWithInference = method.getParamType(i);
Type actualType = argumentsTypes.get(i);
List<TypeParameterDeclaration> typeParameters = method.getDeclaration().getTypeParameters();
typeParameters.addAll(method.declaringType().getTypeParameters());
if (expectedType.describe().equals(actualType.describe())){
return true;
}
Map<TypeParameterDeclaration, Type> derivedValues = new HashMap<>();
for (int j = 0; j < method.getParamTypes().size(); j++) {
ParameterDeclaration parameter = method.getDeclaration().getParam(i);
Type parameterType = parameter.getType();
if (parameter.isVariadic()) {
parameterType = parameterType.asArrayType().getComponentType();
}
inferTypes(argumentsTypes.get(j), parameterType, derivedValues);
}
for (Map.Entry<TypeParameterDeclaration, Type> entry : derivedValues.entrySet()){
TypeParameterDeclaration tp = entry.getKey();
expectedTypeWithInference = expectedTypeWithInference.replaceTypeVariables(tp, entry.getValue());
}
for (TypeParameterDeclaration tp : typeParameters) {
if (tp.getBounds(typeSolver).isEmpty()) {
//expectedType = expectedType.replaceTypeVariables(tp.getName(), new ReferenceTypeUsageImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
expectedType = expectedType.replaceTypeVariables(tp, Wildcard.extendsBound(new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver)));
} else if (tp.getBounds(typeSolver).size() == 1) {
TypeParameterDeclaration.Bound bound = tp.getBounds(typeSolver).get(0);
if (bound.isExtends()) {
//expectedType = expectedType.replaceTypeVariables(tp.getName(), bound.getType());
expectedType = expectedType.replaceTypeVariables(tp, Wildcard.extendsBound(bound.getType()));
} else {
//expectedType = expectedType.replaceTypeVariables(tp.getName(), new ReferenceTypeUsageImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
expectedType = expectedType.replaceTypeVariables(tp, Wildcard.superBound(bound.getType()));
}
} else {
throw new UnsupportedOperationException();
}
}
Type expectedType2 = expectedTypeWithoutSubstitutions;
for (TypeParameterDeclaration tp : typeParameters) {
if (tp.getBounds(typeSolver).isEmpty()) {
expectedType2 = expectedType2.replaceTypeVariables(tp, new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
} else if (tp.getBounds(typeSolver).size() == 1) {
TypeParameterDeclaration.Bound bound = tp.getBounds(typeSolver).get(0);
if (bound.isExtends()) {
expectedType2 = expectedType2.replaceTypeVariables(tp, bound.getType());
} else {
expectedType2 = expectedType2.replaceTypeVariables(tp, new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
}
} else {
throw new UnsupportedOperationException();
}
}
if (!expectedType.isAssignableBy(actualType)
&& !expectedType2.isAssignableBy(actualType)
&& !expectedTypeWithInference.isAssignableBy(actualType)
&& !expectedTypeWithoutSubstitutions.isAssignableBy(actualType)) {
return false;
}
}
return true;
}
private static List<MethodDeclaration> getMethodsWithoutDuplicates(List<MethodDeclaration> methods) {
Set<MethodDeclaration> s = new TreeSet<MethodDeclaration>(new Comparator<MethodDeclaration>() {
@Override
public int compare(MethodDeclaration m1, MethodDeclaration m2) {
if (m1 instanceof JavaParserMethodDeclaration && m2 instanceof JavaParserMethodDeclaration &&
((JavaParserMethodDeclaration) m1).getWrappedNode().equals(((JavaParserMethodDeclaration) m2).getWrappedNode())) {
return 0;
}
return 1;
}
});
s.addAll(methods);
List<MethodDeclaration> res = new ArrayList<>();
Set<String> usedSignatures = new HashSet<>();
for (MethodDeclaration md : methods) {
String signature = md.getQualifiedSignature();
if (!usedSignatures.contains(signature)) {
usedSignatures.add(signature);
res.add(md);
}
}
return res;
}
/**
* @param methods we expect the methods to be ordered such that inherited methods are later in the list
* @param name
* @param argumentsTypes
* @param typeSolver
* @return
*/
public static SymbolReference<MethodDeclaration> findMostApplicable(List<MethodDeclaration> methods, String name, List<Type> argumentsTypes, TypeSolver typeSolver) {
SymbolReference<MethodDeclaration> res = findMostApplicable(methods, name, argumentsTypes, typeSolver, false);
if (res.isSolved()) {
return res;
}
return findMostApplicable(methods, name, argumentsTypes, typeSolver, true);
}
public static SymbolReference<MethodDeclaration> findMostApplicable(List<MethodDeclaration> methods, String name, List<Type> argumentsTypes, TypeSolver typeSolver, boolean wildcardTolerance) {
List<MethodDeclaration> applicableMethods = getMethodsWithoutDuplicates(methods).stream().filter((m) -> isApplicable(m, name, argumentsTypes, typeSolver, wildcardTolerance)).collect(Collectors.toList());
if (applicableMethods.isEmpty()) {
return SymbolReference.unsolved(MethodDeclaration.class);
}
if (applicableMethods.size() > 1) {
List<Integer> nullParamIndexes = new ArrayList<>();
for (int i = 0; i < argumentsTypes.size(); i++) {
if (argumentsTypes.get(i).isNull()) {
nullParamIndexes.add(i);
}
}
if (!nullParamIndexes.isEmpty()) {
// remove method with array param if a non array exists and arg is null
Set<MethodDeclaration> removeCandidates = new HashSet<>();
for (Integer nullParamIndex: nullParamIndexes) {
for (MethodDeclaration methDecl: applicableMethods) {
if (methDecl.getParam(nullParamIndex.intValue()).getType().isArray()) {
removeCandidates.add(methDecl);
}
}
}
if (!removeCandidates.isEmpty() && removeCandidates.size() < applicableMethods.size()) {
applicableMethods.removeAll(removeCandidates);
}
}
}
if (applicableMethods.size() == 1) {
return SymbolReference.solved(applicableMethods.get(0));
} else {
MethodDeclaration winningCandidate = applicableMethods.get(0);
MethodDeclaration other = null;
boolean possibleAmbiguity = false;
for (int i = 1; i < applicableMethods.size(); i++) {
other = applicableMethods.get(i);
if (isMoreSpecific(winningCandidate, other, argumentsTypes, typeSolver)) {
possibleAmbiguity = false;
} else if (isMoreSpecific(other, winningCandidate, argumentsTypes, typeSolver)) {
possibleAmbiguity = false;
winningCandidate = other;
} else {
if (winningCandidate.declaringType().getQualifiedName().equals(other.declaringType().getQualifiedName())) {
possibleAmbiguity = true;
} else {
// we expect the methods to be ordered such that inherited methods are later in the list
}
}
}
if (possibleAmbiguity) {
// pick the first exact match if it exists
if (!isExactMatch(winningCandidate, argumentsTypes)) {
if (isExactMatch(other, argumentsTypes)) {
winningCandidate = other;
} else {
throw new MethodAmbiguityException("Ambiguous method call: cannot find a most applicable method: " + winningCandidate + ", " + other);
}
}
}
return SymbolReference.solved(winningCandidate);
}
}
protected static boolean isExactMatch(MethodLikeDeclaration method, List<Type> argumentsTypes) {
for (int i = 0; i < method.getNumberOfParams(); i++) {
if (!method.getParam(i).getType().equals(argumentsTypes.get(i))) {
return false;
}
}
return true;
}
private static boolean isMoreSpecific(MethodDeclaration methodA, MethodDeclaration methodB, List<Type> argumentTypes, TypeSolver typeSolver) {
boolean oneMoreSpecificFound = false;
if (methodA.getNumberOfParams() < methodB.getNumberOfParams()) {
return true;
}
if (methodA.getNumberOfParams() > methodB.getNumberOfParams()) {
return false;
}
for (int i = 0; i < methodA.getNumberOfParams(); i++) {
Type tdA = methodA.getParam(i).getType();
Type tdB = methodB.getParam(i).getType();
// B is more specific
if (tdB.isAssignableBy(tdA) && !tdA.isAssignableBy(tdB)) {
oneMoreSpecificFound = true;
}
// A is more specific
if (tdA.isAssignableBy(tdB) && !tdB.isAssignableBy(tdA)) {
return false;
}
}
if (!oneMoreSpecificFound) {
int lastIndex = argumentTypes.size() - 1;
if (methodA.hasVariadicParameter() && !methodB.hasVariadicParameter()) {
// if the last argument is an array then m1 is more specific
if (argumentTypes.get(lastIndex).isArray()) {
return true;
}
if (!argumentTypes.get(lastIndex).isArray()) {
return false;
}
}
if (!methodA.hasVariadicParameter() && methodB.hasVariadicParameter()) {
// if the last argument is an array and m1 is not variadic then
// it is not more specific
if (argumentTypes.get(lastIndex).isArray()) {
return false;
}
if (!argumentTypes.get(lastIndex).isArray()) {
return true;
}
}
}
return oneMoreSpecificFound;
}
private static boolean isMoreSpecific(MethodUsage methodA, MethodUsage methodB, TypeSolver typeSolver) {
boolean oneMoreSpecificFound = false;
for (int i = 0; i < methodA.getNoParams(); i++) {
Type tdA = methodA.getParamType(i);
Type tdB = methodB.getParamType(i);
boolean aIsAssignableByB = tdA.isAssignableBy(tdB);
boolean bIsAssignableByA = tdB.isAssignableBy(tdA);
// B is more specific
if (bIsAssignableByA && !aIsAssignableByB) {
oneMoreSpecificFound = true;
}
// A is more specific
if (aIsAssignableByB && !bIsAssignableByA) {
return false;
}
}
return oneMoreSpecificFound;
}
public static Optional<MethodUsage> findMostApplicableUsage(List<MethodUsage> methods, String name, List<Type> argumentsTypes, TypeSolver typeSolver) {
List<MethodUsage> applicableMethods = methods.stream().filter((m) -> isApplicable(m, name, argumentsTypes, typeSolver)).collect(Collectors.toList());
if (applicableMethods.isEmpty()) {
return Optional.empty();
}
if (applicableMethods.size() == 1) {
return Optional.of(applicableMethods.get(0));
} else {
MethodUsage winningCandidate = applicableMethods.get(0);
for (int i = 1; i < applicableMethods.size(); i++) {
MethodUsage other = applicableMethods.get(i);
if (isMoreSpecific(winningCandidate, other, typeSolver)) {
// nothing to do
} else if (isMoreSpecific(other, winningCandidate, typeSolver)) {
winningCandidate = other;
} else {
if (winningCandidate.declaringType().getQualifiedName().equals(other.declaringType().getQualifiedName())) {
if (!areOverride(winningCandidate, other)) {
throw new MethodAmbiguityException("Ambiguous method call: cannot find a most applicable method: " + winningCandidate + ", " + other + ". First declared in " + winningCandidate.declaringType().getQualifiedName());
}
} else {
// we expect the methods to be ordered such that inherited methods are later in the list
//throw new UnsupportedOperationException();
}
}
}
return Optional.of(winningCandidate);
}
}
private static boolean areOverride(MethodUsage winningCandidate, MethodUsage other) {
if (!winningCandidate.getName().equals(other.getName())) {
return false;
}
if (winningCandidate.getNoParams() != other.getNoParams()) {
return false;
}
for (int i = 0; i < winningCandidate.getNoParams(); i++) {
if (!winningCandidate.getParamTypes().get(i).equals(other.getParamTypes().get(i))) {
return false;
}
}
return true;
}
public static SymbolReference<MethodDeclaration> solveMethodInType(TypeDeclaration typeDeclaration, String name, List<Type> argumentsTypes, TypeSolver typeSolver) {
return solveMethodInType(typeDeclaration, name, argumentsTypes, false, typeSolver);
}
/**
* Replace TypeDeclaration.solveMethod
*
* @param typeDeclaration
* @param name
* @param argumentsTypes
* @param staticOnly
* @return
*/
public static SymbolReference<MethodDeclaration> solveMethodInType(TypeDeclaration typeDeclaration,
String name, List<Type> argumentsTypes, boolean staticOnly,
TypeSolver typeSolver) {
if (typeDeclaration instanceof JavaParserClassDeclaration) {
Context ctx = ((JavaParserClassDeclaration) typeDeclaration).getContext();
return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
}
if (typeDeclaration instanceof JavaParserInterfaceDeclaration) {
Context ctx = ((JavaParserInterfaceDeclaration) typeDeclaration).getContext();
return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
}
if (typeDeclaration instanceof JavaParserEnumDeclaration) {
if (name.equals("values") && argumentsTypes.isEmpty()) {
return SymbolReference.solved(new JavaParserEnumDeclaration.ValuesMethod((JavaParserEnumDeclaration) typeDeclaration, typeSolver));
}
Context ctx = ((JavaParserEnumDeclaration) typeDeclaration).getContext();
return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
}
if (typeDeclaration instanceof ReflectionClassDeclaration) {
return ((ReflectionClassDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
}
if (typeDeclaration instanceof ReflectionInterfaceDeclaration) {
return ((ReflectionInterfaceDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
}
if (typeDeclaration instanceof ReflectionEnumDeclaration) {
return ((ReflectionEnumDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
}
if (typeDeclaration instanceof JavassistInterfaceDeclaration) {
return ((JavassistInterfaceDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
}
if (typeDeclaration instanceof JavassistClassDeclaration) {
return ((JavassistClassDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
}
if (typeDeclaration instanceof JavassistEnumDeclaration) {
return ((JavassistEnumDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
}
throw new UnsupportedOperationException(typeDeclaration.getClass().getCanonicalName());
}
private static void inferTypes(Type source, Type target, Map<TypeParameterDeclaration, Type> mappings) {
if (source.equals(target)) {
return;
}
if (source.isReferenceType() && target.isReferenceType()) {
ReferenceType sourceRefType = source.asReferenceType();
ReferenceType 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()) {
return;
}
if (source.isReferenceType() && 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.isWildcard() && target.isTypeVariable()) {
mappings.put(target.asTypeParameter(), source);
return;
}
if (source.isTypeVariable() && target.isTypeVariable()) {
mappings.put(target.asTypeParameter(), source);
return;
}
if (source.isPrimitive() || target.isPrimitive()) {
return;
}
if (source.isNull()) {
return;
}
}
}
@@ -0,0 +1,30 @@
/*
* 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.resolution;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import java.util.List;
/**
* @author Federico Tomassetti
*/
public interface SymbolDeclarator {
List<ValueDeclaration> getSymbolDeclarations();
}
@@ -0,0 +1,164 @@
/*
* 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.resolution;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.javaparsermodel.UnsolvedSymbolException;
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.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ValueDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
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.model.typesystem.Type;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionInterfaceDeclaration;
import java.util.List;
import java.util.Optional;
/**
* @author Federico Tomassetti
*/
public class SymbolSolver {
private TypeSolver typeSolver;
public SymbolSolver(TypeSolver typeSolver) {
if (typeSolver == null) throw new IllegalArgumentException();
this.typeSolver = typeSolver;
}
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, Context context) {
return context.solveSymbol(name, typeSolver);
}
public SymbolReference<? extends ValueDeclaration> solveSymbol(String name, Node node) {
return solveSymbol(name, JavaParserFactory.getContext(node, typeSolver));
}
public Optional<Value> solveSymbolAsValue(String name, Context context) {
return context.solveSymbolAsValue(name, typeSolver);
}
public Optional<Value> solveSymbolAsValue(String name, Node node) {
Context context = JavaParserFactory.getContext(node, typeSolver);
return solveSymbolAsValue(name, context);
}
public SymbolReference<? extends TypeDeclaration> solveType(String name, Context context) {
return context.solveType(name, typeSolver);
}
public SymbolReference<? extends TypeDeclaration> solveType(String name, Node node) {
return solveType(name, JavaParserFactory.getContext(node, typeSolver));
}
public MethodUsage solveMethod(String methodName, List<Type> argumentsTypes, Context context) {
SymbolReference<MethodDeclaration> decl = context.solveMethod(methodName, argumentsTypes, false, typeSolver);
if (!decl.isSolved()) {
throw new UnsolvedSymbolException(context, methodName);
}
return new MethodUsage(decl.getCorrespondingDeclaration());
}
public MethodUsage solveMethod(String methodName, List<Type> argumentsTypes, Node node) {
return solveMethod(methodName, argumentsTypes, JavaParserFactory.getContext(node, typeSolver));
}
public TypeDeclaration solveType(com.github.javaparser.ast.type.Type type) {
if (type instanceof ClassOrInterfaceType) {
// FIXME should call typesolver here!
String name = ((ClassOrInterfaceType) type).getName().getId();
SymbolReference<TypeDeclaration> ref = JavaParserFactory.getContext(type, typeSolver).solveType(name, typeSolver);
if (!ref.isSolved()) {
throw new UnsolvedSymbolException(JavaParserFactory.getContext(type, typeSolver), name);
}
return ref.getCorrespondingDeclaration();
} else {
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
}
public Type solveTypeUsage(String name, Context context) {
Optional<Type> genericType = context.solveGenericType(name, typeSolver);
if (genericType.isPresent()) {
return genericType.get();
}
ReferenceTypeDeclaration typeDeclaration = typeSolver.solveType(name);
ReferenceTypeImpl typeUsage = new ReferenceTypeImpl(typeDeclaration, typeSolver);
return typeUsage;
}
/**
* Solve any possible visible symbols including: fields, internal types, type variables, the type itself or its
* containers.
* <p>
* It should contain its own private fields but not inherited private fields.
*/
public SymbolReference<? extends ValueDeclaration> solveSymbolInType(TypeDeclaration typeDeclaration, String name) {
if (typeDeclaration instanceof JavaParserClassDeclaration) {
Context ctx = ((JavaParserClassDeclaration) typeDeclaration).getContext();
return ctx.solveSymbol(name, typeSolver);
}
if (typeDeclaration instanceof JavaParserInterfaceDeclaration) {
Context ctx = ((JavaParserInterfaceDeclaration) typeDeclaration).getContext();
return ctx.solveSymbol(name, typeSolver);
}
if (typeDeclaration instanceof JavaParserEnumDeclaration) {
Context ctx = ((JavaParserEnumDeclaration) typeDeclaration).getContext();
return ctx.solveSymbol(name, typeSolver);
}
if (typeDeclaration instanceof ReflectionClassDeclaration) {
return ((ReflectionClassDeclaration) typeDeclaration).solveSymbol(name, typeSolver);
}
if (typeDeclaration instanceof ReflectionInterfaceDeclaration) {
return ((ReflectionInterfaceDeclaration) typeDeclaration).solveSymbol(name, typeSolver);
}
if (typeDeclaration instanceof JavassistClassDeclaration) {
return ((JavassistClassDeclaration) typeDeclaration).solveSymbol(name, typeSolver);
}
return SymbolReference.unsolved(ValueDeclaration.class);
}
/**
* Try to solve a symbol just in the declaration, it does not delegate to the container.
*/
@Deprecated
public SymbolReference<TypeDeclaration> solveTypeInType(TypeDeclaration typeDeclaration, String name) {
if (typeDeclaration instanceof JavaParserClassDeclaration) {
return ((JavaParserClassDeclaration) typeDeclaration).solveType(name, typeSolver);
}
if (typeDeclaration instanceof JavaParserInterfaceDeclaration) {
return ((JavaParserInterfaceDeclaration) typeDeclaration).solveType(name, typeSolver);
}
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
}
@@ -0,0 +1,76 @@
/*
* 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.resolution.typesolvers;
import com.github.javaparser.symbolsolver.javaparsermodel.UnsolvedSymbolException;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.util.ArrayList;
import java.util.List;
/**
* @author Federico Tomassetti
*/
public class CombinedTypeSolver implements TypeSolver {
private TypeSolver parent;
private List<TypeSolver> elements = new ArrayList<>();
public CombinedTypeSolver(TypeSolver... elements) {
for (TypeSolver el : elements) {
add(el);
}
}
@Override
public TypeSolver getParent() {
return parent;
}
@Override
public void setParent(TypeSolver parent) {
this.parent = parent;
}
public void add(TypeSolver typeSolver) {
this.elements.add(typeSolver);
typeSolver.setParent(this);
}
@Override
public SymbolReference<ReferenceTypeDeclaration> tryToSolveType(String name) {
for (TypeSolver ts : elements) {
SymbolReference<ReferenceTypeDeclaration> res = ts.tryToSolveType(name);
if (res.isSolved()) {
return res;
}
}
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
@Override
public ReferenceTypeDeclaration solveType(String name) throws UnsolvedSymbolException {
SymbolReference<ReferenceTypeDeclaration> res = tryToSolveType(name);
if (res.isSolved()) {
return res.getCorrespondingDeclaration();
} else {
throw new UnsolvedSymbolException(name);
}
}
}
@@ -0,0 +1,138 @@
/*
* 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.resolution.typesolvers;
import com.github.javaparser.symbolsolver.javassistmodel.JavassistFactory;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @author Federico Tomassetti
*/
public class JarTypeSolver implements TypeSolver {
private static JarTypeSolver instance;
private TypeSolver parent;
private Map<String, ClasspathElement> classpathElements = new HashMap<>();
private ClassPool classPool = new ClassPool(false);
public JarTypeSolver(String pathToJar) throws IOException {
addPathToJar(pathToJar);
}
public static JarTypeSolver getJarTypeSolver(String pathToJar) throws IOException {
if (instance == null) {
instance = new JarTypeSolver(pathToJar);
} else {
instance.addPathToJar(pathToJar);
}
return instance;
}
private void addPathToJar(String pathToJar) throws IOException {
try {
classPool.appendClassPath(pathToJar);
classPool.appendSystemPath();
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
JarFile jarFile = new JarFile(pathToJar);
JarEntry entry = null;
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
entry = e.nextElement();
if (entry != null && !entry.isDirectory() && entry.getName().endsWith(".class")) {
String name = entryPathToClassName(entry.getName());
classpathElements.put(name, new ClasspathElement(jarFile, entry, name));
}
}
}
@Override
public TypeSolver getParent() {
return parent;
}
@Override
public void setParent(TypeSolver parent) {
this.parent = parent;
}
private String entryPathToClassName(String entryPath) {
if (!entryPath.endsWith(".class")) {
throw new IllegalStateException();
}
String className = entryPath.substring(0, entryPath.length() - ".class".length());
className = className.replace('/', '.');
className = className.replace('$', '.');
return className;
}
@Override
public SymbolReference<ReferenceTypeDeclaration> tryToSolveType(String name) {
try {
if (classpathElements.containsKey(name)) {
return SymbolReference.solved(
JavassistFactory.toTypeDeclaration(classpathElements.get(name).toCtClass(), getRoot()));
} else {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public ReferenceTypeDeclaration solveType(String name) throws UnsolvedSymbolException {
SymbolReference<ReferenceTypeDeclaration> ref = tryToSolveType(name);
if (ref.isSolved()) {
return ref.getCorrespondingDeclaration();
} else {
throw new UnsolvedSymbolException(name);
}
}
private class ClasspathElement {
private JarFile jarFile;
private JarEntry entry;
private String path;
ClasspathElement(JarFile jarFile, JarEntry entry, String path) {
this.jarFile = jarFile;
this.entry = entry;
this.path = path;
}
CtClass toCtClass() throws IOException {
try (InputStream is = jarFile.getInputStream(entry)) {
return classPool.makeClass(is);
}
}
}
}
@@ -0,0 +1,158 @@
/*
* 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.resolution.typesolvers;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.symbolsolver.javaparser.Navigator;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* @author Federico Tomassetti
*/
public class JavaParserTypeSolver implements TypeSolver {
private File srcDir;
private TypeSolver parent;
private Map<String, CompilationUnit> parsedFiles = new HashMap<String, CompilationUnit>();
private Map<String, List<CompilationUnit>> parsedDirectories = new HashMap<>();
private Map<String, ReferenceTypeDeclaration> foundTypes=new HashMap<>();
public JavaParserTypeSolver(File srcDir) {
this.srcDir = srcDir;
}
@Override
public String toString() {
return "JavaParserTypeSolver{" +
"srcDir=" + srcDir +
", parent=" + parent +
'}';
}
@Override
public TypeSolver getParent() {
return parent;
}
@Override
public void setParent(TypeSolver parent) {
this.parent = parent;
}
private CompilationUnit parse(File srcFile) throws FileNotFoundException {
if (!parsedFiles.containsKey(srcFile.getAbsolutePath())) {
parsedFiles.put(srcFile.getAbsolutePath(), JavaParser.parse(srcFile));
}
return parsedFiles.get(srcFile.getAbsolutePath());
}
private List<CompilationUnit> parseDirectory(File srcDirectory) throws FileNotFoundException {
if (!parsedDirectories.containsKey(srcDirectory.getAbsolutePath())) {
List<CompilationUnit> units = new ArrayList<>();
File[] files = srcDirectory.listFiles();
if (files == null) throw new FileNotFoundException(srcDirectory.getAbsolutePath());
for (File file : files) {
if (file.getName().toLowerCase().endsWith(".java")) {
units.add(parse(file));
}
}
parsedDirectories.put(srcDirectory.getAbsolutePath(), units);
}
return parsedDirectories.get(srcDirectory.getAbsolutePath());
}
@Override
public SymbolReference<ReferenceTypeDeclaration> tryToSolveType(String name) {
if (!srcDir.exists() || !srcDir.isDirectory()) {
throw new IllegalStateException("SrcDir does not exist or is not a directory: " + srcDir.getAbsolutePath());
}
// TODO support enums
// TODO support interfaces
if (foundTypes.containsKey(name))
return SymbolReference.solved(foundTypes.get(name));
SymbolReference<ReferenceTypeDeclaration> result = tryToSolveTypeUncached(name);
if (result.isSolved()) {
foundTypes.put(name, result.getCorrespondingDeclaration());
}
return result;
}
private SymbolReference<ReferenceTypeDeclaration> tryToSolveTypeUncached(String name) {
String[] nameElements = name.split("\\.");
for (int i = nameElements.length; i > 0; i--) {
String filePath = srcDir.getAbsolutePath();
for (int j = 0; j < i; j++) {
filePath += "/" + nameElements[j];
}
filePath += ".java";
String typeName = "";
for (int j = i - 1; j < nameElements.length; j++) {
if (j != i - 1) {
typeName += ".";
}
typeName += nameElements[j];
}
File srcFile = new File(filePath);
try {
CompilationUnit compilationUnit = parse(srcFile);
Optional<com.github.javaparser.ast.body.TypeDeclaration<?>> astTypeDeclaration = Navigator.findType(compilationUnit, typeName);
if (astTypeDeclaration.isPresent()) {
return SymbolReference.solved(JavaParserFacade.get(this).getTypeDeclaration(astTypeDeclaration.get()));
}
} catch (FileNotFoundException e) {
// Ignore
}
try {
List<CompilationUnit> compilationUnits = parseDirectory(srcFile.getParentFile());
for (CompilationUnit compilationUnit : compilationUnits) {
Optional<com.github.javaparser.ast.body.TypeDeclaration<?>> astTypeDeclaration = Navigator.findType(compilationUnit, typeName);
if (astTypeDeclaration.isPresent()) {
return SymbolReference.solved(JavaParserFacade.get(this).getTypeDeclaration(astTypeDeclaration.get()));
}
}
} catch (FileNotFoundException e) {
// Ignore
}
}
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
}
@@ -0,0 +1,86 @@
/*
* 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.resolution.typesolvers;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.util.HashMap;
import java.util.Map;
/**
* A TypeSolver which only consider the TypeDeclarations provided to it.
*
* @author Federico Tomassetti
*/
public class MemoryTypeSolver implements TypeSolver {
private TypeSolver parent;
private Map<String, ReferenceTypeDeclaration> declarationMap = new HashMap<>();
@Override
public String toString() {
return "MemoryTypeSolver{" +
"parent=" + parent +
", declarationMap=" + declarationMap +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MemoryTypeSolver)) return false;
MemoryTypeSolver that = (MemoryTypeSolver) o;
if (parent != null ? !parent.equals(that.parent) : that.parent != null) return false;
return !(declarationMap != null ? !declarationMap.equals(that.declarationMap) : that.declarationMap != null);
}
@Override
public int hashCode() {
int result = parent != null ? parent.hashCode() : 0;
result = 31 * result + (declarationMap != null ? declarationMap.hashCode() : 0);
return result;
}
@Override
public TypeSolver getParent() {
return parent;
}
@Override
public void setParent(TypeSolver parent) {
this.parent = parent;
}
public void addDeclaration(String name, ReferenceTypeDeclaration typeDeclaration) {
this.declarationMap.put(name, typeDeclaration);
}
@Override
public SymbolReference<ReferenceTypeDeclaration> tryToSolveType(String name) {
if (declarationMap.containsKey(name)) {
return SymbolReference.solved(declarationMap.get(name));
} else {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
}
}
@@ -0,0 +1,94 @@
/*
* 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.resolution.typesolvers;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionFactory;
import java.util.Optional;
/**
* @author Federico Tomassetti
*/
public class ReflectionTypeSolver implements TypeSolver {
private TypeSolver parent;
public ReflectionTypeSolver(boolean jreOnly) {
this.jreOnly = jreOnly;
}
public ReflectionTypeSolver() {
this(true);
}
private boolean jreOnly;
@Override
public TypeSolver getParent() {
return parent;
}
@Override
public void setParent(TypeSolver parent) {
this.parent = parent;
}
@Override
public SymbolReference<ReferenceTypeDeclaration> tryToSolveType(String name) {
if (!jreOnly || (name.startsWith("java.") || name.startsWith("javax."))) {
try {
ClassLoader classLoader = ReflectionTypeSolver.class.getClassLoader();
// Some implementations could return null when the class was loaded through the bootstrap classloader
// see https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getClassLoader--
if (classLoader == null) {
throw new RuntimeException("The ReflectionTypeSolver has been probably loaded through the bootstrap class loader. This usage is not supported by the JavaSymbolSolver");
}
Class<?> clazz = classLoader.loadClass(name);
return SymbolReference.solved(ReflectionFactory.typeDeclarationFor(clazz, getRoot()));
} catch (ClassNotFoundException e) {
// it could be an inner class
int lastDot = name.lastIndexOf('.');
if (lastDot == -1) {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
} else {
String parentName = name.substring(0, lastDot);
String childName = name.substring(lastDot + 1);
SymbolReference<ReferenceTypeDeclaration> parent = tryToSolveType(parentName);
if (parent.isSolved()) {
Optional<ReferenceTypeDeclaration> innerClass = parent.getCorrespondingDeclaration().internalTypes()
.stream().filter(it -> it.getName().equals(childName)).findFirst();
if (innerClass.isPresent()) {
return SymbolReference.solved(innerClass.get());
} else {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
} else {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
}
}
} else {
return SymbolReference.unsolved(ReferenceTypeDeclaration.class);
}
}
}
@@ -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.logic;
import com.github.javaparser.symbolsolver.model.declarations.ClassDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import java.util.ArrayList;
import java.util.List;
/**
* A common ancestor for all ClassDeclarations.
*
* @author Federico Tomassetti
*/
public abstract class AbstractClassDeclaration extends AbstractTypeDeclaration implements ClassDeclaration {
///
/// Public
///
@Override
public boolean hasName() {
return getQualifiedName() != null;
}
@Override
public final List<ReferenceType> getAllSuperClasses() {
List<ReferenceType> superclasses = new ArrayList<>();
ReferenceType superClass = getSuperClass();
if (superClass != null) {
superclasses.add(superClass);
superclasses.addAll(superClass.getAllClassesAncestors());
}
if (superclasses.removeIf(s -> s.getQualifiedName().equals(Object.class.getCanonicalName()))) {
superclasses.add(object());
}
return superclasses;
}
@Override
public final List<ReferenceType> getAllInterfaces() {
List<ReferenceType> interfaces = new ArrayList<>();
for (ReferenceType interfaceDeclaration : getInterfaces()) {
interfaces.add(interfaceDeclaration);
interfaces.addAll(interfaceDeclaration.getAllInterfacesAncestors());
}
ReferenceType superClass = this.getSuperClass();
if (superClass != null) {
interfaces.addAll(superClass.getAllInterfacesAncestors());
}
return interfaces;
}
@Override
public final ClassDeclaration asClass() {
return this;
}
///
/// Protected
///
/**
* An implementation of the Object class.
*/
protected abstract ReferenceType object();
}
@@ -0,0 +1,65 @@
/*
* 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.logic;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Common ancestor for most types.
*
* @author Federico Tomassetti
*/
public abstract class AbstractTypeDeclaration implements ReferenceTypeDeclaration {
@Override
public final Set<MethodUsage> getAllMethods() {
Set<MethodUsage> methods = new HashSet<>();
Set<String> methodsSignatures = new HashSet<>();
for (MethodDeclaration methodDeclaration : getDeclaredMethods()) {
methods.add(new MethodUsage(methodDeclaration));
methodsSignatures.add(methodDeclaration.getSignature());
}
for (ReferenceType ancestor : getAllAncestors()) {
for (MethodUsage mu : ancestor.getDeclaredMethods()) {
String signature = mu.getDeclaration().getSignature();
if (!methodsSignatures.contains(signature)) {
methodsSignatures.add(signature);
methods.add(mu);
}
}
}
return methods;
}
@Override
public final boolean isFunctionalInterface() {
return FunctionalInterfaceLogic.getFunctionalMethod(this).isPresent();
}
}
@@ -0,0 +1,13 @@
package com.github.javaparser.symbolsolver.logic;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
/**
* @author Federico Tomassetti
*/
public class ConfilictingGenericTypesException extends RuntimeException {
public ConfilictingGenericTypesException(Type formalType, Type actualType) {
super(String.format("No matching between %s (formal) and %s (actual)", formalType, actualType));
}
}
@@ -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.logic;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public final class FunctionalInterfaceLogic {
private FunctionalInterfaceLogic() {
// prevent instantiation
}
/**
* Get the functional method defined by the type, if any.
*/
public static Optional<MethodUsage> getFunctionalMethod(Type type) {
if (type.isReferenceType() && type.asReferenceType().getTypeDeclaration().isInterface()) {
return getFunctionalMethod(type.asReferenceType().getTypeDeclaration());
} else {
return Optional.empty();
}
}
/**
* Get the functional method defined by the type, if any.
*/
public static Optional<MethodUsage> getFunctionalMethod(ReferenceTypeDeclaration typeDeclaration) {
//We need to find all abstract methods
Set<MethodUsage> methods = typeDeclaration.getAllMethods().stream()
.filter(m -> m.getDeclaration().isAbstract())
// Remove methods inherited by Object:
// Consider the case of Comparator which define equals. It would be considered a functional method.
.filter(m -> !declaredOnObject(m))
.collect(Collectors.toSet());
if (methods.size() == 1) {
return Optional.of(methods.iterator().next());
} else {
return Optional.empty();
}
}
private static String getSignature(Method m) {
return String.format("%s(%s)", m.getName(), String.join(", ", Arrays.stream(m.getParameters()).map(p -> toSignature(p)).collect(Collectors.toList())));
}
private static String toSignature(Parameter p) {
return p.getType().getCanonicalName();
}
private static List<String> OBJECT_METHODS_SIGNATURES = Arrays.stream(Object.class.getDeclaredMethods())
.map(method -> getSignature(method))
.collect(Collectors.toList());
private static boolean declaredOnObject(MethodUsage m) {
return OBJECT_METHODS_SIGNATURES.contains(m.getDeclaration().getSignature());
}
}
@@ -0,0 +1,209 @@
/*
* 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.logic;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.typesystem.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class InferenceContext {
private int nextInferenceVariableId = 0;
private ObjectProvider objectProvider;
private List<InferenceVariableType> inferenceVariableTypes = new ArrayList<>();
public InferenceContext(ObjectProvider objectProvider) {
this.objectProvider = objectProvider;
}
private Map<String, InferenceVariableType> inferenceVariableTypeMap = new HashMap<>();
private InferenceVariableType inferenceVariableTypeForTp(TypeParameterDeclaration tp) {
if (!inferenceVariableTypeMap.containsKey(tp.getName())) {
InferenceVariableType inferenceVariableType = new InferenceVariableType(nextInferenceVariableId++, objectProvider);
inferenceVariableTypes.add(inferenceVariableType);
inferenceVariableType.setCorrespondingTp(tp);
inferenceVariableTypeMap.put(tp.getName(), inferenceVariableType);
}
return inferenceVariableTypeMap.get(tp.getName());
}
/**
*
* @return the actual with the inference variable inserted
*/
public Type addPair(Type target, Type actual) {
target = placeInferenceVariables(target);
actual = placeInferenceVariables(actual);
registerCorrespondance(target, actual);
return target;
}
public Type addSingle(Type actual) {
return placeInferenceVariables(actual);
}
private void registerCorrespondance(Type formalType, Type actualType) {
if (formalType.isReferenceType() && actualType.isReferenceType()) {
ReferenceType formalTypeAsReference = formalType.asReferenceType();
ReferenceType actualTypeAsReference = actualType.asReferenceType();
if (!formalTypeAsReference.getQualifiedName().equals(actualTypeAsReference.getQualifiedName())) {
List<ReferenceType> ancestors = actualTypeAsReference.getAllAncestors();
final String formalParamTypeQName = formalTypeAsReference.getQualifiedName();
List<Type> correspondingFormalType = ancestors.stream().filter((a) -> a.getQualifiedName().equals(formalParamTypeQName)).collect(Collectors.toList());
if (correspondingFormalType.isEmpty()) {
ancestors = formalTypeAsReference.getAllAncestors();
final String actualParamTypeQname = actualTypeAsReference.getQualifiedName();
List<Type> correspondingActualType = ancestors.stream().filter(a -> a.getQualifiedName().equals(actualParamTypeQname)).collect(Collectors.toList());
if (correspondingActualType.isEmpty()){
throw new ConfilictingGenericTypesException(formalType, actualType);
}
correspondingFormalType = correspondingActualType;
}
actualTypeAsReference = correspondingFormalType.get(0).asReferenceType();
}
if (formalTypeAsReference.getQualifiedName().equals(actualTypeAsReference.getQualifiedName())) {
if (!formalTypeAsReference.typeParametersValues().isEmpty()) {
if (actualTypeAsReference.isRawType()) {
// nothing to do
} else {
int i = 0;
for (Type formalTypeParameter : formalTypeAsReference.typeParametersValues()) {
registerCorrespondance(formalTypeParameter, actualTypeAsReference.typeParametersValues().get(i));
i++;
}
}
}
}
} else if (formalType instanceof InferenceVariableType && !actualType.isPrimitive()) {
((InferenceVariableType) formalType).registerEquivalentType(actualType);
if (actualType instanceof InferenceVariableType) {
((InferenceVariableType) actualType).registerEquivalentType(formalType);
}
} else if (actualType.isNull()) {
// nothing to do
} else if (actualType.equals(formalType)) {
// nothing to do
} else if (actualType.isArray() && formalType.isArray()) {
registerCorrespondance(formalType.asArrayType().getComponentType(), actualType.asArrayType().getComponentType());
} else if (formalType.isWildcard()) {
// nothing to do
if ((actualType instanceof InferenceVariableType) && formalType.asWildcard().isBounded()) {
((InferenceVariableType) actualType).registerEquivalentType(formalType.asWildcard().getBoundedType());
if (formalType.asWildcard().getBoundedType() instanceof InferenceVariableType) {
((InferenceVariableType) formalType.asWildcard().getBoundedType()).registerEquivalentType(actualType);
}
}
if (actualType.isWildcard()) {
Wildcard formalWildcard = formalType.asWildcard();
Wildcard actualWildcard = actualType.asWildcard();
if (formalWildcard.isBounded() && formalWildcard.getBoundedType() instanceof InferenceVariableType) {
if (formalWildcard.isSuper() && actualWildcard.isSuper()) {
((InferenceVariableType) formalType.asWildcard().getBoundedType()).registerEquivalentType(actualWildcard.getBoundedType());
} else if (formalWildcard.isExtends() && actualWildcard.isExtends()) {
((InferenceVariableType) formalType.asWildcard().getBoundedType()).registerEquivalentType(actualWildcard.getBoundedType());
}
}
}
if (actualType.isReferenceType()){
if (formalType.asWildcard().isBounded()){
registerCorrespondance(formalType.asWildcard().getBoundedType(), actualType);
}
}
} else if (actualType instanceof InferenceVariableType){
if (formalType instanceof ReferenceType){
((InferenceVariableType) actualType).registerEquivalentType(formalType);
} else if (formalType instanceof InferenceVariableType){
((InferenceVariableType) actualType).registerEquivalentType(formalType);
}
} else if (actualType.isConstraint()){
LambdaConstraintType constraintType = actualType.asConstraintType();
if (constraintType.getBound() instanceof InferenceVariableType){
((InferenceVariableType) constraintType.getBound()).registerEquivalentType(formalType);
}
} else if (actualType.isPrimitive()) {
if (formalType.isPrimitive()) {
// nothing to do
} else {
registerCorrespondance(formalType, objectProvider.byName(actualType.asPrimitive().getBoxTypeQName()));
}
} else {
throw new UnsupportedOperationException(formalType.describe() + " " + actualType.describe());
}
}
private Type placeInferenceVariables(Type type) {
if (type.isWildcard()) {
if (type.asWildcard().isExtends()) {
return Wildcard.extendsBound(placeInferenceVariables(type.asWildcard().getBoundedType()));
} else if (type.asWildcard().isSuper()) {
return Wildcard.superBound(placeInferenceVariables(type.asWildcard().getBoundedType()));
} else {
return type;
}
} else if (type.isTypeVariable()) {
return inferenceVariableTypeForTp(type.asTypeParameter());
} else if (type.isReferenceType()) {
return type.asReferenceType().transformTypeParameters(tp -> placeInferenceVariables(tp));
} else if (type.isArray()) {
return new ArrayType(placeInferenceVariables(type.asArrayType().getComponentType()));
} else if (type.isNull() || type.isPrimitive() || type.isVoid()) {
return type;
} else if (type.isConstraint()){
return LambdaConstraintType.bound(placeInferenceVariables(type.asConstraintType().getBound()));
} else if (type instanceof InferenceVariableType) {
return type;
} else {
throw new UnsupportedOperationException(type.describe());
}
}
public Type resolve(Type type) {
if (type instanceof InferenceVariableType) {
InferenceVariableType inferenceVariableType = (InferenceVariableType) type;
return inferenceVariableType.equivalentType();
} else if (type.isReferenceType()) {
return type.asReferenceType().transformTypeParameters(tp -> resolve(tp));
} else if (type.isNull() || type.isPrimitive() || type.isVoid()) {
return type;
} else if (type.isArray()) {
return new ArrayType(resolve(type.asArrayType().getComponentType()));
} else if (type.isWildcard()) {
if (type.asWildcard().isExtends()) {
return Wildcard.extendsBound(resolve(type.asWildcard().getBoundedType()));
} else if (type.asWildcard().isSuper()) {
return Wildcard.superBound(resolve(type.asWildcard().getBoundedType()));
} else {
return type;
}
} else {
throw new UnsupportedOperationException(type.describe());
}
}
}
@@ -0,0 +1,164 @@
/*
* 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.logic;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.model.typesystem.TypeVariable;
import com.github.javaparser.symbolsolver.model.typesystem.Wildcard;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* An element using during type inference.
*
* @author Federico Tomassetti
*/
public class InferenceVariableType implements Type {
@Override
public String toString() {
return "InferenceVariableType{" +
"id=" + id +
'}';
}
private int id;
private TypeParameterDeclaration correspondingTp;
public void setCorrespondingTp(TypeParameterDeclaration correspondingTp) {
this.correspondingTp = correspondingTp;
}
private Set<Type> equivalentTypes = new HashSet<>();
private ObjectProvider objectProvider;
public void registerEquivalentType(Type type) {
this.equivalentTypes.add(type);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof InferenceVariableType)) return false;
InferenceVariableType that = (InferenceVariableType) o;
return id == that.id;
}
@Override
public int hashCode() {
return id;
}
private Set<Type> superTypes = new HashSet<>();
public InferenceVariableType(int id, ObjectProvider objectProvider) {
this.id = id;
this.objectProvider = objectProvider;
}
public static InferenceVariableType fromWildcard(Wildcard wildcard, int id, ObjectProvider objectProvider) {
InferenceVariableType inferenceVariableType = new InferenceVariableType(id, objectProvider);
if (wildcard.isExtends()) {
inferenceVariableType.superTypes.add(wildcard.getBoundedType());
}
if (wildcard.isSuper()) {
// I am not sure about this one...
inferenceVariableType.superTypes.add(wildcard.getBoundedType());
}
return inferenceVariableType;
}
@Override
public String describe() {
return "InferenceVariable_" + id;
}
@Override
public boolean isAssignableBy(Type other) {
throw new UnsupportedOperationException();
}
private Set<Type> concreteEquivalentTypesAlsoIndirectly(Set<InferenceVariableType> considered, InferenceVariableType inferenceVariableType) {
considered.add(inferenceVariableType);
Set<Type> result = new HashSet<>();
result.addAll(inferenceVariableType.equivalentTypes.stream().filter(t -> !t.isTypeVariable() && !(t instanceof InferenceVariableType)).collect(Collectors.toSet()));
inferenceVariableType.equivalentTypes.stream().filter(t -> t instanceof InferenceVariableType).forEach(t -> {
InferenceVariableType ivt = (InferenceVariableType)t;
if (!considered.contains(ivt)) {
result.addAll(concreteEquivalentTypesAlsoIndirectly(considered, ivt));
}
});
return result;
}
public Type equivalentType() {
Set<Type> concreteEquivalent = concreteEquivalentTypesAlsoIndirectly(new HashSet<>(), this);
if (concreteEquivalent.isEmpty()) {
if (correspondingTp == null) {
return objectProvider.object();
} else {
return new TypeVariable(correspondingTp);
}
}
if (concreteEquivalent.size() == 1) {
return concreteEquivalent.iterator().next();
}
Set<Type> notTypeVariables = equivalentTypes.stream()
.filter(t -> !t.isTypeVariable() && !hasInferenceVariables(t))
.collect(Collectors.toSet());
if (notTypeVariables.size() == 1) {
return notTypeVariables.iterator().next();
} else if (notTypeVariables.size() == 0 && !superTypes.isEmpty()) {
if (superTypes.size() == 1) {
return superTypes.iterator().next();
} else {
throw new IllegalStateException("Super types are: " + superTypes);
}
} else {
throw new IllegalStateException("Equivalent types are: " + equivalentTypes);
}
}
private boolean hasInferenceVariables(Type type){
if (type instanceof InferenceVariableType){
return true;
}
if (type.isReferenceType()){
ReferenceType refType = type.asReferenceType();
for (Type t : refType.typeParametersValues()){
if (hasInferenceVariables(t)){
return true;
}
}
return false;
}
if (type.isWildcard()){
Wildcard wildcardType = type.asWildcard();
return hasInferenceVariables(wildcardType.getBoundedType());
}
return false;
}
}
@@ -0,0 +1,27 @@
/*
* 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.logic;
import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
/**
* @author Federico Tomassetti
*/
public interface ObjectProvider {
ReferenceType object();
ReferenceType byName(String qname);
}
@@ -0,0 +1,27 @@
/*
* 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.model.declarations;
/**
* @author Federico Tomassetti
*/
public enum AccessLevel {
PUBLIC,
PRIVATE,
PROTECTED,
PACKAGE_PROTECTED
}

Some files were not shown because too many files have changed in this diff Show More