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 17package com.github.javaparser.symbolsolver.javaparsermodel.contexts; 18 19import com.github.javaparser.ast.CompilationUnit; 20import com.github.javaparser.ast.ImportDeclaration; 21import com.github.javaparser.ast.body.AnnotationDeclaration; 22import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 23import com.github.javaparser.ast.body.EnumDeclaration; 24import com.github.javaparser.ast.body.TypeDeclaration; 25import com.github.javaparser.ast.expr.MethodCallExpr; 26import com.github.javaparser.ast.expr.Name; 27import com.github.javaparser.ast.type.ClassOrInterfaceType; 28import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; 29import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; 30import com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration; 31import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; 32import com.github.javaparser.resolution.types.ResolvedType; 33import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 34import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnnotationDeclaration; 35import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration; 36import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 37import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 38import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic; 39import com.github.javaparser.symbolsolver.resolution.SymbolSolver; 40 41import java.util.List; 42 43/** 44 * @author Federico Tomassetti 45 */ 46public class CompilationUnitContext extends AbstractJavaParserContext<CompilationUnit> { 47 48 /// 49 /// Static methods 50 /// 51 52 private static boolean isQualifiedName(String name) { 53 return name.contains("."); 54 } 55 56 /// 57 /// Constructors 58 /// 59 60 public CompilationUnitContext(CompilationUnit wrappedNode, TypeSolver typeSolver) { 61 super(wrappedNode, typeSolver); 62 } 63 64 /// 65 /// Public methods 66 /// 67 68 @Override 69 public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { 70 71 // solve absolute references 72 String itName = name; 73 while (itName.contains(".")) { 74 String typeName = getType(itName); 75 String memberName = getMember(itName); 76 SymbolReference<ResolvedTypeDeclaration> type = this.solveType(typeName, typeSolver); 77 if (type.isSolved()) { 78 return new SymbolSolver(typeSolver).solveSymbolInType(type.getCorrespondingDeclaration(), memberName); 79 } else { 80 itName = typeName; 81 } 82 } 83 84 // Look among statically imported values 85 if (wrappedNode.getImports() != null) { 86 for (ImportDeclaration importDecl : wrappedNode.getImports()) { 87 if(importDecl.isStatic()){ 88 if(importDecl.isAsterisk()) { 89 String qName = importDecl.getNameAsString(); 90 ResolvedTypeDeclaration importedType = typeSolver.solveType(qName); 91 SymbolReference<? extends ResolvedValueDeclaration> ref = new SymbolSolver(typeSolver).solveSymbolInType(importedType, name); 92 if (ref.isSolved()) { 93 return ref; 94 } 95 } else{ 96 String whole = importDecl.getNameAsString(); 97 98 // split in field/method name and type name 99 String memberName = getMember(whole); 100 String typeName = getType(whole); 101 102 if (memberName.equals(name)) { 103 ResolvedTypeDeclaration importedType = typeSolver.solveType(typeName); 104 return new SymbolSolver(typeSolver).solveSymbolInType(importedType, memberName); 105 } 106 } 107 } 108 } 109 } 110 111 return SymbolReference.unsolved(ResolvedValueDeclaration.class); 112 } 113 114 @Override 115 public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { 116 if (wrappedNode.getTypes() != null) { 117 for (TypeDeclaration<?> type : wrappedNode.getTypes()) { 118 if (type.getName().getId().equals(name)) { 119 if (type instanceof ClassOrInterfaceDeclaration) { 120 return SymbolReference.solved(JavaParserFacade.get(typeSolver).getTypeDeclaration((ClassOrInterfaceDeclaration) type)); 121 } else if (type instanceof AnnotationDeclaration) { 122 return SymbolReference.solved(new JavaParserAnnotationDeclaration((AnnotationDeclaration) type, typeSolver)); 123 } else if (type instanceof EnumDeclaration) { 124 return SymbolReference.solved(new JavaParserEnumDeclaration((EnumDeclaration) type, typeSolver)); 125 } else { 126 throw new UnsupportedOperationException(type.getClass().getCanonicalName()); 127 } 128 } 129 } 130 } 131 132 if (wrappedNode.getImports() != null) { 133 int dotPos = name.indexOf('.'); 134 String prefix = null; 135 if (dotPos > -1) { 136 prefix = name.substring(0, dotPos); 137 } 138 // look into type imports 139 for (ImportDeclaration importDecl : wrappedNode.getImports()) { 140 if (!importDecl.isAsterisk()) { 141 String qName = importDecl.getNameAsString(); 142 boolean defaultPackage = !importDecl.getName().getQualifier().isPresent(); 143 boolean found = !defaultPackage && importDecl.getName().getIdentifier().equals(name); 144 if (!found) { 145 if (prefix != null) { 146 found = qName.endsWith("." + prefix); 147 if (found) { 148 qName = qName + name.substring(dotPos); 149 } 150 } 151 } 152 if (found) { 153 SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); 154 if (ref.isSolved()) { 155 return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); 156 } 157 } 158 } 159 } 160 // look into type imports on demand 161 for (ImportDeclaration importDecl : wrappedNode.getImports()) { 162 if (importDecl.isAsterisk()) { 163 String qName = importDecl.getNameAsString() + "." + name; 164 SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); 165 if (ref.isSolved()) { 166 return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); 167 } 168 } 169 } 170 } 171 172 // Look in current package 173 if (this.wrappedNode.getPackageDeclaration().isPresent()) { 174 String qName = this.wrappedNode.getPackageDeclaration().get().getName().toString() + "." + name; 175 SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); 176 if (ref.isSolved()) { 177 return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); 178 } 179 } else { 180 // look for classes in the default package 181 String qName = name; 182 SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType(qName); 183 if (ref.isSolved()) { 184 return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); 185 } 186 } 187 188 // Look in the java.lang package 189 SymbolReference<ResolvedReferenceTypeDeclaration> ref = typeSolver.tryToSolveType("java.lang." + name); 190 if (ref.isSolved()) { 191 return SymbolReference.adapt(ref, ResolvedTypeDeclaration.class); 192 } 193 194 // DO NOT look for absolute name if this name is not qualified: you cannot import classes from the default package 195 if (isQualifiedName(name)) { 196 return SymbolReference.adapt(typeSolver.tryToSolveType(name), ResolvedTypeDeclaration.class); 197 } else { 198 return SymbolReference.unsolved(ResolvedReferenceTypeDeclaration.class); 199 } 200 } 201 202 private String qName(ClassOrInterfaceType type) { 203 if (type.getScope().isPresent()) { 204 return qName(type.getScope().get()) + "." + type.getName().getId(); 205 } else { 206 return type.getName().getId(); 207 } 208 } 209 210 private String qName(Name name) { 211 if (name.getQualifier().isPresent()) { 212 return qName(name.getQualifier().get()) + "." + name.getId(); 213 } else { 214 return name.getId(); 215 } 216 } 217 218 private String toSimpleName(String qName) { 219 String[] parts = qName.split("\\."); 220 return parts[parts.length - 1]; 221 } 222 223 private String packageName(String qName) { 224 int lastDot = qName.lastIndexOf('.'); 225 if (lastDot == -1) { 226 throw new UnsupportedOperationException(); 227 } else { 228 return qName.substring(0, lastDot); 229 } 230 } 231 232 @Override 233 public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly, TypeSolver typeSolver) { 234 for (ImportDeclaration importDecl : wrappedNode.getImports()) { 235 if(importDecl.isStatic()){ 236 if(importDecl.isAsterisk()){ 237 String importString = importDecl.getNameAsString(); 238 239 if (this.wrappedNode.getPackageDeclaration().isPresent() 240 && this.wrappedNode.getPackageDeclaration().get().getName().getIdentifier().equals(packageName(importString)) 241 && this.wrappedNode.getTypes().stream().anyMatch(it -> it.getName().getIdentifier().equals(toSimpleName(importString)))) { 242 // We are using a static import on a type defined in this file. It means the value was not found at 243 // a lower level so this will fail 244 return SymbolReference.unsolved(ResolvedMethodDeclaration.class); 245 } 246 247 ResolvedTypeDeclaration ref = typeSolver.solveType(importString); 248 SymbolReference<ResolvedMethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver); 249 250 if (method.isSolved()) { 251 return method; 252 } 253 } else{ 254 String qName = importDecl.getNameAsString(); 255 256 if (qName.equals(name) || qName.endsWith("." + name)) { 257 String typeName = getType(qName); 258 ResolvedTypeDeclaration ref = typeSolver.solveType(typeName); 259 SymbolReference<ResolvedMethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver); 260 if (method.isSolved()) { 261 return method; 262 } 263 } 264 } 265 } 266 } 267 return SymbolReference.unsolved(ResolvedMethodDeclaration.class); 268 } 269 270 /// 271 /// Private methods 272 /// 273 274 private String getType(String qName) { 275 int index = qName.lastIndexOf('.'); 276 if (index == -1) { 277 throw new UnsupportedOperationException(); 278 } 279 String typeName = qName.substring(0, index); 280 return typeName; 281 } 282 283 private String getMember(String qName) { 284 int index = qName.lastIndexOf('.'); 285 if (index == -1) { 286 throw new UnsupportedOperationException(); 287 } 288 String memberName = qName.substring(index + 1); 289 return memberName; 290 } 291} 292