• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Federico Tomassetti
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.github.javaparser.symbolsolver.javaparsermodel.contexts;
18 
19 import com.github.javaparser.ast.Node;
20 import com.github.javaparser.ast.expr.Expression;
21 import com.github.javaparser.ast.expr.FieldAccessExpr;
22 import com.github.javaparser.ast.expr.MethodCallExpr;
23 import com.github.javaparser.ast.expr.NameExpr;
24 import com.github.javaparser.resolution.UnsolvedSymbolException;
25 import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
26 import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration;
27 import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
28 import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
29 import com.github.javaparser.resolution.types.ResolvedReferenceType;
30 import com.github.javaparser.resolution.types.ResolvedType;
31 import com.github.javaparser.symbolsolver.core.resolution.Context;
32 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
33 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
34 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
35 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
36 import com.github.javaparser.symbolsolver.model.resolution.Value;
37 import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
38 import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
39 
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.Optional;
44 
45 import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode;
46 import static java.util.Collections.singletonList;
47 
48 /**
49  * @author Federico Tomassetti
50  */
51 public abstract class AbstractJavaParserContext<N extends Node> implements Context {
52 
53     protected N wrappedNode;
54     protected TypeSolver typeSolver;
55 
56     ///
57     /// Static methods
58     ///
59 
solveWith(SymbolDeclarator symbolDeclarator, String name)60     public static SymbolReference<ResolvedValueDeclaration> solveWith(SymbolDeclarator symbolDeclarator, String name) {
61         for (ResolvedValueDeclaration decl : symbolDeclarator.getSymbolDeclarations()) {
62             if (decl.getName().equals(name)) {
63                 return SymbolReference.solved(decl);
64             }
65         }
66         return SymbolReference.unsolved(ResolvedValueDeclaration.class);
67     }
68 
69     ///
70     /// Constructors
71     ///
72 
AbstractJavaParserContext(N wrappedNode, TypeSolver typeSolver)73     public AbstractJavaParserContext(N wrappedNode, TypeSolver typeSolver) {
74         if (wrappedNode == null) {
75             throw new NullPointerException();
76         }
77         this.wrappedNode = wrappedNode;
78         this.typeSolver = typeSolver;
79     }
80 
81     ///
82     /// Public methods
83     ///
84 
85     @Override
equals(Object o)86     public boolean equals(Object o) {
87         if (this == o) return true;
88         if (o == null || getClass() != o.getClass()) return false;
89 
90         AbstractJavaParserContext<?> that = (AbstractJavaParserContext<?>) o;
91 
92         return wrappedNode != null ? wrappedNode.equals(that.wrappedNode) : that.wrappedNode == null;
93     }
94 
95     @Override
hashCode()96     public int hashCode() {
97         return wrappedNode != null ? wrappedNode.hashCode() : 0;
98     }
99 
100     @Override
solveGenericType(String name)101     public Optional<ResolvedType> solveGenericType(String name) {
102         Context parent = getParent();
103         if (parent == null) {
104             return Optional.empty();
105         } else {
106             return parent.solveGenericType(name);
107         }
108     }
109 
110     @Override
getParent()111     public final Context getParent() {
112         Node parent = wrappedNode.getParentNode().orElse(null);
113         if (parent instanceof MethodCallExpr) {
114             MethodCallExpr parentCall = (MethodCallExpr) parent;
115             boolean found = false;
116             if (parentCall.getArguments() != null) {
117                 for (Expression expression : parentCall.getArguments()) {
118                     if (expression == wrappedNode) {
119                         found = true;
120                     }
121                 }
122             }
123             if (found) {
124                 Node notMethod = parent;
125                 while (notMethod instanceof MethodCallExpr) {
126                     notMethod = requireParentNode(notMethod);
127                 }
128                 return JavaParserFactory.getContext(notMethod, typeSolver);
129             }
130         }
131         Node notMethod = parent;
132         while (notMethod instanceof MethodCallExpr || notMethod instanceof FieldAccessExpr) {
133             notMethod = notMethod.getParentNode().orElse(null);
134         }
135         if (notMethod == null) {
136             return null;
137         }
138         return JavaParserFactory.getContext(notMethod, typeSolver);
139     }
140 
141     ///
142     /// Protected methods
143     ///
144 
solveWithAsValue(SymbolDeclarator symbolDeclarator, String name)145     protected Optional<Value> solveWithAsValue(SymbolDeclarator symbolDeclarator, String name) {
146         return symbolDeclarator.getSymbolDeclarations().stream()
147                 .filter(d -> d.getName().equals(name))
148                 .map(Value::from)
149                 .findFirst();
150     }
151 
findTypeDeclarations(Optional<Expression> optScope)152     protected Collection<ResolvedReferenceTypeDeclaration> findTypeDeclarations(Optional<Expression> optScope) {
153         if (optScope.isPresent()) {
154             Expression scope = optScope.get();
155 
156             // consider static methods
157             if (scope instanceof NameExpr) {
158                 NameExpr scopeAsName = scope.asNameExpr();
159                 SymbolReference<ResolvedTypeDeclaration> symbolReference = this.solveType(scopeAsName.getName().getId());
160                 if (symbolReference.isSolved() && symbolReference.getCorrespondingDeclaration().isType()) {
161                     return singletonList(symbolReference.getCorrespondingDeclaration().asReferenceType());
162                 }
163             }
164 
165             ResolvedType typeOfScope;
166             try {
167                 typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
168             } catch (Exception e) {
169                 // If the scope corresponds to a type we should treat it differently
170                 if (scope instanceof FieldAccessExpr) {
171                     FieldAccessExpr scopeName = (FieldAccessExpr) scope;
172                     if (this.solveType(scopeName.toString()).isSolved()) {
173                         return Collections.emptyList();
174                     }
175                 }
176                 throw new UnsolvedSymbolException(scope.toString(), wrappedNode.toString(), e);
177             }
178             if (typeOfScope.isWildcard()) {
179                 if (typeOfScope.asWildcard().isExtends() || typeOfScope.asWildcard().isSuper()) {
180                     return singletonList(typeOfScope.asWildcard().getBoundedType().asReferenceType().getTypeDeclaration());
181                 } else {
182                     return singletonList(new ReflectionClassDeclaration(Object.class, typeSolver).asReferenceType());
183                 }
184             } else if (typeOfScope.isArray()) {
185                 // method call on array are Object methods
186                 return singletonList(new ReflectionClassDeclaration(Object.class, typeSolver).asReferenceType());
187             } else if (typeOfScope.isTypeVariable()) {
188                 Collection<ResolvedReferenceTypeDeclaration> result = new ArrayList<>();
189                 for (ResolvedTypeParameterDeclaration.Bound bound : typeOfScope.asTypeParameter().getBounds()) {
190                     result.add(bound.getType().asReferenceType().getTypeDeclaration());
191                 }
192                 return result;
193             } else if (typeOfScope.isConstraint()) {
194                 return singletonList(typeOfScope.asConstraintType().getBound().asReferenceType().getTypeDeclaration());
195             } else if (typeOfScope.isUnionType()) {
196                 return typeOfScope.asUnionType().getCommonAncestor()
197                         .map(ResolvedReferenceType::getTypeDeclaration)
198                         .map(Collections::singletonList)
199                         .orElseThrow(() -> new UnsolvedSymbolException("No common ancestor available for UnionType"
200                                 + typeOfScope.describe()));
201             }
202             return singletonList(typeOfScope.asReferenceType().getTypeDeclaration());
203         }
204         ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
205         return singletonList(typeOfScope.asReferenceType().getTypeDeclaration());
206     }
207 
getWrappedNode()208     public N getWrappedNode() {
209         return wrappedNode;
210     }
211 }
212