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