src: added test for indexing JavaSymbolSolver 0.6.0
* made DumpParserClient reusable by java tests
This commit is contained in:
+216
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+98
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -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);
|
||||
}
|
||||
}
|
||||
+295
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -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;
|
||||
+465
@@ -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());
|
||||
}
|
||||
}
|
||||
+531
@@ -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);
|
||||
}
|
||||
}
|
||||
+135
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+523
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+67
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+138
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -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);
|
||||
}
|
||||
}
|
||||
+186
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -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);
|
||||
}
|
||||
}
|
||||
+108
@@ -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);
|
||||
}
|
||||
}
|
||||
+285
@@ -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;
|
||||
}
|
||||
}
|
||||
+35
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+71
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -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);
|
||||
}
|
||||
}
|
||||
+93
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -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);
|
||||
}
|
||||
}
|
||||
+60
@@ -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);
|
||||
}
|
||||
}
|
||||
+133
@@ -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);
|
||||
}
|
||||
}
|
||||
+194
@@ -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();
|
||||
}
|
||||
}
|
||||
+476
@@ -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;
|
||||
}
|
||||
}
|
||||
+36
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+200
@@ -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);
|
||||
}
|
||||
}
|
||||
+80
@@ -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);
|
||||
}
|
||||
}
|
||||
+82
@@ -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);
|
||||
}
|
||||
}
|
||||
+64
@@ -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();
|
||||
}
|
||||
}
|
||||
+89
@@ -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;
|
||||
}
|
||||
}
|
||||
+92
@@ -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());
|
||||
}
|
||||
}
|
||||
+203
@@ -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());
|
||||
}
|
||||
}
|
||||
+381
@@ -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);
|
||||
}
|
||||
}
|
||||
+82
@@ -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());
|
||||
}
|
||||
}
|
||||
+59
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+340
@@ -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();
|
||||
}
|
||||
}
|
||||
+123
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+319
@@ -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);
|
||||
}
|
||||
}
|
||||
+149
@@ -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());
|
||||
}
|
||||
}
|
||||
+88
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+177
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+120
@@ -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();
|
||||
}
|
||||
}
|
||||
+224
@@ -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();
|
||||
}
|
||||
}
|
||||
+187
@@ -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();
|
||||
}
|
||||
}
|
||||
+35
@@ -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;
|
||||
}
|
||||
}
|
||||
+46
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -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;
|
||||
}
|
||||
}
|
||||
+52
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -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;
|
||||
+383
@@ -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));
|
||||
}
|
||||
}
|
||||
+122
@@ -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());
|
||||
}
|
||||
}
|
||||
+231
@@ -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));
|
||||
}
|
||||
}
|
||||
+84
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -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);
|
||||
}
|
||||
}
|
||||
+280
@@ -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));
|
||||
}
|
||||
}
|
||||
+165
@@ -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();
|
||||
}
|
||||
}
|
||||
+80
@@ -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;
|
||||
}
|
||||
}
|
||||
+93
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+117
@@ -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();
|
||||
}
|
||||
}
|
||||
+177
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -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;
|
||||
+117
@@ -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);
|
||||
}
|
||||
}
|
||||
+148
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+36
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+190
@@ -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));
|
||||
}
|
||||
}
|
||||
+343
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -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());
|
||||
}
|
||||
}
|
||||
+191
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+118
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
@@ -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());
|
||||
}
|
||||
}
|
||||
+305
@@ -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());
|
||||
}
|
||||
}
|
||||
+135
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
+144
@@ -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;
|
||||
}
|
||||
}
|
||||
+75
@@ -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);
|
||||
}
|
||||
}
|
||||
+130
@@ -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();
|
||||
}
|
||||
}
|
||||
+25
@@ -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;
|
||||
}
|
||||
}
|
||||
+25
@@ -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;
|
||||
}
|
||||
}
|
||||
+19
@@ -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;
|
||||
}
|
||||
}
|
||||
+20
@@ -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;
|
||||
+226
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+679
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+30
@@ -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();
|
||||
|
||||
}
|
||||
+164
@@ -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);
|
||||
}
|
||||
}
|
||||
+76
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+138
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+158
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+86
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+94
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -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();
|
||||
|
||||
}
|
||||
+65
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -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));
|
||||
}
|
||||
}
|
||||
+85
@@ -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());
|
||||
}
|
||||
}
|
||||
+209
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
+164
@@ -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;
|
||||
}
|
||||
}
|
||||
+27
@@ -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);
|
||||
}
|
||||
+27
@@ -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
Reference in New Issue
Block a user