-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
JavaParserTypeDeclarationAdapter.java
133 lines (119 loc) · 7.29 KB
/
JavaParserTypeDeclarationAdapter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package com.github.javaparser.symbolsolver.javaparsermodel.contexts;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters;
import com.github.javaparser.ast.type.TypeParameter;
import com.github.javaparser.resolution.declarations.*;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.reflectionmodel.*;
import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic;
import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
public class JavaParserTypeDeclarationAdapter {
private com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode;
private TypeSolver typeSolver;
private Context context;
private ResolvedReferenceTypeDeclaration typeDeclaration;
public JavaParserTypeDeclarationAdapter(com.github.javaparser.ast.body.TypeDeclaration<?> wrappedNode, TypeSolver typeSolver,
ResolvedReferenceTypeDeclaration typeDeclaration,
Context context) {
this.wrappedNode = wrappedNode;
this.typeSolver = typeSolver;
this.typeDeclaration = typeDeclaration;
this.context = context;
}
public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) {
if (this.wrappedNode.getName().getId().equals(name)) {
return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(wrappedNode));
}
// Internal classes
for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) {
if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) {
com.github.javaparser.ast.body.TypeDeclaration<?> internalType = (com.github.javaparser.ast.body.TypeDeclaration<?>) member;
if (internalType.getName().getId().equals(name)) {
return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration(internalType));
} else if (name.startsWith(String.format("%s.%s", wrappedNode.getName(), internalType.getName()))) {
return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(wrappedNode.getName().getId().length() + 1), typeSolver);
} else if (name.startsWith(String.format("%s.", internalType.getName()))) {
return JavaParserFactory.getContext(internalType, typeSolver).solveType(name.substring(internalType.getName().getId().length() + 1), typeSolver);
}
}
}
if (wrappedNode instanceof NodeWithTypeParameters) {
NodeWithTypeParameters<?> nodeWithTypeParameters = (NodeWithTypeParameters<?>) wrappedNode;
for (TypeParameter astTpRaw : nodeWithTypeParameters.getTypeParameters()) {
TypeParameter astTp = astTpRaw;
if (astTp.getName().getId().equals(name)) {
return SymbolReference.solved(new JavaParserTypeParameter(astTp, typeSolver));
}
}
}
// Look into extended classes and implemented interfaces
for (ResolvedReferenceType ancestor : this.typeDeclaration.getAncestors()) {
try {
for (ResolvedTypeDeclaration internalTypeDeclaration : ancestor.getTypeDeclaration().internalTypes()) {
if (internalTypeDeclaration.getName().equals(name)) {
return SymbolReference.solved(internalTypeDeclaration);
}
}
} catch (UnsupportedOperationException e) {
// just continue using the next ancestor
}
}
return context.getParent().solveType(name, typeSolver);
}
public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) {
List<ResolvedMethodDeclaration> candidateMethods = typeDeclaration.getDeclaredMethods().stream()
.filter(m -> m.getName().equals(name))
.filter(m -> !staticOnly || (staticOnly && m.isStatic()))
.collect(Collectors.toList());
// We want to avoid infinite recursion in case of Object having Object as ancestor
if (!Object.class.getCanonicalName().equals(typeDeclaration.getQualifiedName())) {
for (ResolvedReferenceType ancestor : typeDeclaration.getAncestors()) {
// Avoid recursion on self
if (typeDeclaration != ancestor.getTypeDeclaration()) {
SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic
.solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver);
// consider methods from superclasses and only default methods from interfaces :
// not true, we should keep abstract as a valid candidate
// abstract are removed in MethodResolutionLogic.isApplicable is necessary
if (res.isSolved()) {
candidateMethods.add(res.getCorrespondingDeclaration());
}
}
}
}
// We want to avoid infinite recursion when a class is using its own method
// see issue #75
if (candidateMethods.isEmpty()) {
SymbolReference<ResolvedMethodDeclaration> parentSolution = context.getParent().solveMethod(name, argumentsTypes, staticOnly, typeSolver);
if (parentSolution.isSolved()) {
candidateMethods.add(parentSolution.getCorrespondingDeclaration());
}
}
// if is interface and candidate method list is empty, we should check the Object Methods
if (candidateMethods.isEmpty() && typeDeclaration.isInterface()) {
SymbolReference<ResolvedMethodDeclaration> res = MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver);
if (res.isSolved()) {
candidateMethods.add(res.getCorrespondingDeclaration());
}
}
return MethodResolutionLogic.findMostApplicable(candidateMethods, name, argumentsTypes, typeSolver);
}
public SymbolReference<ResolvedConstructorDeclaration> solveConstructor(List<ResolvedType> argumentsTypes, TypeSolver typeSolver) {
if (typeDeclaration instanceof ResolvedClassDeclaration) {
return ConstructorResolutionLogic.findMostApplicable(((ResolvedClassDeclaration) typeDeclaration).getConstructors(), argumentsTypes, typeSolver);
}
return SymbolReference.unsolved(ResolvedConstructorDeclaration.class);
}
}