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.declarations; 18 19 import com.github.javaparser.ast.AccessSpecifier; 20 import com.github.javaparser.ast.Node; 21 import com.github.javaparser.ast.body.BodyDeclaration; 22 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 23 import com.github.javaparser.ast.expr.AnnotationExpr; 24 import com.github.javaparser.ast.type.ClassOrInterfaceType; 25 import com.github.javaparser.resolution.UnsolvedSymbolException; 26 import com.github.javaparser.resolution.declarations.*; 27 import com.github.javaparser.resolution.types.ResolvedReferenceType; 28 import com.github.javaparser.resolution.types.ResolvedType; 29 import com.github.javaparser.symbolsolver.core.resolution.Context; 30 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 31 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; 32 import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; 33 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 34 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 35 import com.github.javaparser.symbolsolver.model.typesystem.LazyType; 36 import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; 37 import com.github.javaparser.symbolsolver.resolution.SymbolSolver; 38 39 import java.util.*; 40 import java.util.stream.Collectors; 41 42 /** 43 * @author Federico Tomassetti 44 */ 45 public class JavaParserInterfaceDeclaration extends AbstractTypeDeclaration implements ResolvedInterfaceDeclaration { 46 47 private TypeSolver typeSolver; 48 private ClassOrInterfaceDeclaration wrappedNode; 49 private JavaParserTypeAdapter<ClassOrInterfaceDeclaration> javaParserTypeAdapter; 50 51 public JavaParserInterfaceDeclaration(ClassOrInterfaceDeclaration wrappedNode, TypeSolver typeSolver) { 52 if (!wrappedNode.isInterface()) { 53 throw new IllegalArgumentException(); 54 } 55 this.wrappedNode = wrappedNode; 56 this.typeSolver = typeSolver; 57 this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver); 58 } 59 60 @Override 61 public Set<ResolvedMethodDeclaration> getDeclaredMethods() { 62 Set<ResolvedMethodDeclaration> methods = new HashSet<>(); 63 for (BodyDeclaration<?> member : wrappedNode.getMembers()) { 64 if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { 65 methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver)); 66 } 67 } 68 return methods; 69 } 70 71 public Context getContext() { 72 return JavaParserFactory.getContext(wrappedNode, typeSolver); 73 } 74 75 public ResolvedType getUsage(Node node) { 76 throw new UnsupportedOperationException(); 77 } 78 79 @Override 80 public boolean equals(Object o) { 81 if (this == o) return true; 82 if (o == null || getClass() != o.getClass()) return false; 83 84 JavaParserInterfaceDeclaration that = (JavaParserInterfaceDeclaration) o; 85 86 if (!wrappedNode.equals(that.wrappedNode)) return false; 87 88 return true; 89 } 90 91 @Override 92 public int hashCode() { 93 return wrappedNode.hashCode(); 94 } 95 96 @Override 97 public String getName() { 98 return wrappedNode.getName().getId(); 99 } 100 101 @Override 102 public ResolvedInterfaceDeclaration asInterface() { 103 return this; 104 } 105 106 @Override 107 public boolean hasDirectlyAnnotation(String canonicalName) { 108 for (AnnotationExpr annotationExpr : wrappedNode.getAnnotations()) { 109 if (solveType(annotationExpr.getName().getId(), typeSolver).getCorrespondingDeclaration().getQualifiedName().equals(canonicalName)) { 110 return true; 111 } 112 } 113 return false; 114 } 115 116 @Override 117 public boolean isInterface() { 118 return true; 119 } 120 121 @Override 122 public List<ResolvedReferenceType> getInterfacesExtended() { 123 List<ResolvedReferenceType> interfaces = new ArrayList<>(); 124 if (wrappedNode.getImplementedTypes() != null) { 125 for (ClassOrInterfaceType t : wrappedNode.getImplementedTypes()) { 126 interfaces.add(new ReferenceTypeImpl(solveType(t.getName().getId(), typeSolver).getCorrespondingDeclaration().asInterface(), typeSolver)); 127 } 128 } 129 return interfaces; 130 } 131 132 @Override 133 public String getPackageName() { 134 return javaParserTypeAdapter.getPackageName(); 135 } 136 137 @Override 138 public String getClassName() { 139 return javaParserTypeAdapter.getClassName(); 140 } 141 142 @Override 143 public String getQualifiedName() { 144 return javaParserTypeAdapter.getQualifiedName(); 145 } 146 147 @Override 148 public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { 149 return javaParserTypeAdapter.isAssignableBy(other); 150 } 151 152 @Override 153 public boolean isAssignableBy(ResolvedType type) { 154 return javaParserTypeAdapter.isAssignableBy(type); 155 } 156 157 @Override 158 public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { 159 // TODO consider generic types 160 if (this.getQualifiedName().equals(other.getQualifiedName())) { 161 return true; 162 } 163 if (this.wrappedNode.getExtendedTypes() != null) { 164 for (ClassOrInterfaceType type : wrappedNode.getExtendedTypes()) { 165 ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type); 166 if (ancestor.canBeAssignedTo(other)) { 167 return true; 168 } 169 } 170 } 171 172 if (this.wrappedNode.getImplementedTypes() != null) { 173 for (ClassOrInterfaceType type : wrappedNode.getImplementedTypes()) { 174 ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type); 175 if (ancestor.canBeAssignedTo(other)) { 176 return true; 177 } 178 } 179 } 180 181 return false; 182 } 183 184 @Override 185 public boolean isTypeParameter() { 186 return false; 187 } 188 189 @Override 190 public List<ResolvedFieldDeclaration> getAllFields() { 191 List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables(); 192 193 getAncestors().forEach(ancestor -> ancestor.getTypeDeclaration().getAllFields().forEach(f -> { 194 fields.add(new ResolvedFieldDeclaration() { 195 196 @Override 197 public AccessSpecifier accessSpecifier() { 198 return f.accessSpecifier(); 199 } 200 201 @Override 202 public String getName() { 203 return f.getName(); 204 } 205 206 @Override 207 public ResolvedType getType() { 208 return ancestor.useThisTypeParametersOnTheGivenType(f.getType()); 209 } 210 211 @Override 212 public boolean isStatic() { 213 return f.isStatic(); 214 } 215 216 @Override 217 public ResolvedTypeDeclaration declaringType() { 218 return f.declaringType(); 219 } 220 }); 221 })); 222 223 return fields; 224 } 225 226 227 @Override 228 public String toString() { 229 return "JavaParserInterfaceDeclaration{" + 230 "wrappedNode=" + wrappedNode + 231 '}'; 232 } 233 234 @Deprecated 235 public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { 236 if (this.wrappedNode.getName().getId().equals(name)) { 237 return SymbolReference.solved(this); 238 } 239 SymbolReference<ResolvedTypeDeclaration> ref = javaParserTypeAdapter.solveType(name, typeSolver); 240 if (ref.isSolved()) { 241 return ref; 242 } 243 244 String prefix = wrappedNode.getName() + "."; 245 if (name.startsWith(prefix) && name.length() > prefix.length()) { 246 return new JavaParserInterfaceDeclaration(this.wrappedNode, typeSolver).solveType(name.substring(prefix.length()), typeSolver); 247 } 248 249 return getContext().getParent().solveType(name, typeSolver); 250 } 251 252 @Override 253 public List<ResolvedReferenceType> getAncestors() { 254 List<ResolvedReferenceType> ancestors = new ArrayList<>(); 255 if (wrappedNode.getExtendedTypes() != null) { 256 for (ClassOrInterfaceType extended : wrappedNode.getExtendedTypes()) { 257 ancestors.add(toReferenceType(extended)); 258 } 259 } 260 if (wrappedNode.getImplementedTypes() != null) { 261 for (ClassOrInterfaceType implemented : wrappedNode.getImplementedTypes()) { 262 ancestors.add(toReferenceType(implemented)); 263 } 264 } 265 return ancestors; 266 } 267 268 @Override 269 public List<ResolvedTypeParameterDeclaration> getTypeParameters() { 270 if (this.wrappedNode.getTypeParameters() == null) { 271 return Collections.emptyList(); 272 } else { 273 return this.wrappedNode.getTypeParameters().stream().map( 274 (tp) -> new JavaParserTypeParameter(tp, typeSolver) 275 ).collect(Collectors.toList()); 276 } 277 } 278 279 /** 280 * Returns the JavaParser node associated with this JavaParserInterfaceDeclaration. 281 * 282 * @return A visitable JavaParser node wrapped by this object. 283 */ 284 public ClassOrInterfaceDeclaration getWrappedNode() { 285 return wrappedNode; 286 } 287 288 @Override 289 public AccessSpecifier accessSpecifier() { 290 return Helper.toAccessLevel(wrappedNode.getModifiers()); 291 } 292 293 @Override 294 public Set<ResolvedReferenceTypeDeclaration> internalTypes() { 295 Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>(); 296 for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { 297 if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { 298 res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member)); 299 } 300 } 301 return res; 302 } 303 304 @Override 305 public Optional<ResolvedReferenceTypeDeclaration> containerType() { 306 return javaParserTypeAdapter.containerType(); 307 } 308 309 /// 310 /// Private methods 311 /// 312 313 private ResolvedReferenceType toReferenceType(ClassOrInterfaceType classOrInterfaceType) { 314 SymbolReference<? extends ResolvedTypeDeclaration> ref = null; 315 if (classOrInterfaceType.toString().indexOf('.') > -1) { 316 ref = typeSolver.tryToSolveType(classOrInterfaceType.toString()); 317 } 318 if (ref == null || !ref.isSolved()) { 319 ref = solveType(classOrInterfaceType.toString(), typeSolver); 320 } 321 if (!ref.isSolved()) { 322 ref = solveType(classOrInterfaceType.getName().getId(), typeSolver); 323 } 324 if (!ref.isSolved()) { 325 throw new UnsolvedSymbolException(classOrInterfaceType.getName().getId()); 326 } 327 if (!classOrInterfaceType.getTypeArguments().isPresent()) { 328 return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), typeSolver); 329 } 330 List<ResolvedType> superClassTypeParameters = classOrInterfaceType.getTypeArguments().get() 331 .stream().map(ta -> new LazyType(v -> JavaParserFacade.get(typeSolver).convert(ta, ta))) 332 .collect(Collectors.toList()); 333 return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), superClassTypeParameters, typeSolver); 334 } 335 } 336