1 /* 2 * Copyright (C) 2007-2010 Júlio Vilmar Gesser. 3 * Copyright (C) 2011, 2013-2016 The JavaParser Team. 4 * 5 * This file is part of JavaParser. 6 * 7 * JavaParser can be used either under the terms of 8 * a) the GNU Lesser General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * b) the terms of the Apache License 12 * 13 * You should have received a copy of both licenses in LICENCE.LGPL and 14 * LICENCE.APACHE. Please refer to those files for details. 15 * 16 * JavaParser is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU Lesser General Public License for more details. 20 */ 21 22 package com.github.javaparser.resolution.declarations; 23 24 import com.github.javaparser.ast.AccessSpecifier; 25 import com.github.javaparser.ast.Modifier; 26 import com.github.javaparser.resolution.MethodUsage; 27 import com.github.javaparser.resolution.UnsolvedSymbolException; 28 import com.github.javaparser.resolution.types.ResolvedReferenceType; 29 import com.github.javaparser.resolution.types.ResolvedType; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.Optional; 34 import java.util.Set; 35 import java.util.stream.Collectors; 36 37 /** 38 * @author Federico Tomassetti 39 */ 40 public interface ResolvedReferenceTypeDeclaration extends ResolvedTypeDeclaration, 41 ResolvedTypeParametrizable { 42 43 @Override asReferenceType()44 default ResolvedReferenceTypeDeclaration asReferenceType() { 45 return this; 46 } 47 48 /// 49 /// Ancestors 50 /// 51 52 /** 53 * Resolves the types of all direct ancestors (i.e., the directly extended class and the directly implemented 54 * interfaces) and returns the list of ancestors as a list of resolved reference types. 55 * <p> 56 * In case any ancestor cannot be resolved, an {@code UnsolvedSymbolException} is thrown. In order to obtain a list 57 * of only the resolvable direct ancestors, use {@link #getAncestors(boolean)} and pass the value {@code true}. 58 * <p> 59 * Note that an ancestor can be parametrized types with values specified. For example: 60 * <p> 61 * class A implements Comparable<String> {} 62 * <p> 63 * In this case the ancestor is Comparable<String> 64 * 65 * @return The list of resolved ancestors. 66 * @throws UnsolvedSymbolException if some ancestor could not be resolved. 67 */ getAncestors()68 default List<ResolvedReferenceType> getAncestors() { 69 return getAncestors(false); 70 } 71 72 /** 73 * Resolves the types of all direct ancestors (i.e., the directly extended class and the directly implemented 74 * interfaces) and returns the list of ancestors as a list of resolved reference types. 75 * <p> 76 * If {@code acceptIncompleteList} is {@code false}, then an {@code UnsolvedSymbolException} is thrown if any 77 * ancestor cannot be resolved. Otherwise, a list of only the resolvable direct ancestors is returned. 78 * 79 * @param acceptIncompleteList When set to {@code false}, this method throws an {@link UnsolvedSymbolException} if 80 * one or more ancestor could not be resolved. When set to {@code true}, this method 81 * does not throw an {@link UnsolvedSymbolException}, but the list of returned ancestors 82 * may be incomplete in case one or more ancestor could not be resolved. 83 * @return The list of resolved ancestors. 84 * @throws UnsolvedSymbolException if some ancestor could not be resolved and {@code acceptIncompleteList} is set to 85 * {@code false}. 86 */ getAncestors(boolean acceptIncompleteList)87 List<ResolvedReferenceType> getAncestors(boolean acceptIncompleteList); 88 89 /** 90 * The list of all the ancestors of the current declaration, direct and indirect. 91 * This list does not contains duplicates with the exacting same type parameters. 92 */ getAllAncestors()93 default List<ResolvedReferenceType> getAllAncestors() { 94 List<ResolvedReferenceType> ancestors = new ArrayList<>(); 95 // We want to avoid infinite recursion in case of Object having Object as ancestor 96 if (!(Object.class.getCanonicalName().equals(getQualifiedName()))) { 97 for (ResolvedReferenceType ancestor : getAncestors()) { 98 ancestors.add(ancestor); 99 for (ResolvedReferenceType inheritedAncestor : ancestor.getAllAncestors()) { 100 if (!ancestors.contains(inheritedAncestor)) { 101 ancestors.add(inheritedAncestor); 102 } 103 } 104 } 105 } 106 return ancestors; 107 } 108 109 /// 110 /// Fields 111 /// 112 113 /** 114 * Note that the type of the field should be expressed using the type variables of this particular type. 115 * Consider for example: 116 * <p> 117 * class Foo<E> { E field; } 118 * <p> 119 * class Bar extends Foo<String> { } 120 * <p> 121 * When calling getField("field") on Foo I should get a FieldDeclaration with type E, while calling it on 122 * Bar I should get a FieldDeclaration with type String. 123 */ getField(String name)124 default ResolvedFieldDeclaration getField(String name) { 125 Optional<ResolvedFieldDeclaration> field = this.getAllFields().stream().filter(f -> f.getName().equals(name)).findFirst(); 126 if (field.isPresent()) { 127 return field.get(); 128 } else { 129 throw new UnsolvedSymbolException("Field not found: " + name); 130 } 131 } 132 133 /** 134 * Consider only field or inherited field which is not private. 135 */ getVisibleField(String name)136 default ResolvedFieldDeclaration getVisibleField(String name) { 137 Optional<ResolvedFieldDeclaration> field = getVisibleFields().stream().filter(f -> f.getName().equals(name)).findFirst(); 138 if (field.isPresent()) { 139 return field.get(); 140 } else { 141 throw new IllegalArgumentException(); 142 } 143 } 144 145 /** 146 * Has this type a field with the given name? 147 */ hasField(String name)148 default boolean hasField(String name) { 149 return this.getAllFields().stream().anyMatch(f -> f.getName().equals(name)); 150 } 151 152 /** 153 * Either a declared field or inherited field which is not private. 154 */ hasVisibleField(String name)155 default boolean hasVisibleField(String name) { 156 return getVisibleFields().stream().anyMatch(f -> f.getName().equals(name)); 157 } 158 159 /** 160 * Return a list of all fields, either declared in this declaration or inherited. 161 */ getAllFields()162 List<ResolvedFieldDeclaration> getAllFields(); 163 164 /** 165 * Return a list of all fields declared and the inherited ones which are not private. 166 */ getVisibleFields()167 default List<ResolvedFieldDeclaration> getVisibleFields() { 168 return getAllFields().stream() 169 .filter(f -> f.declaringType().equals(this) || f.accessSpecifier() != AccessSpecifier.PRIVATE) 170 .collect(Collectors.toList()); 171 } 172 173 /** 174 * Return a list of all the non static fields, either declared or inherited. 175 */ getAllNonStaticFields()176 default List<ResolvedFieldDeclaration> getAllNonStaticFields() { 177 return getAllFields().stream().filter(it -> !it.isStatic()).collect(Collectors.toList()); 178 } 179 180 /** 181 * Return a list of all the static fields, either declared or inherited. 182 */ getAllStaticFields()183 default List<ResolvedFieldDeclaration> getAllStaticFields() { 184 return getAllFields().stream().filter(it -> it.isStatic()).collect(Collectors.toList()); 185 } 186 187 /** 188 * Return a list of all the fields declared in this type. 189 */ getDeclaredFields()190 default List<ResolvedFieldDeclaration> getDeclaredFields() { 191 return getAllFields().stream().filter(it -> it.declaringType().getQualifiedName() 192 .equals(getQualifiedName())).collect(Collectors.toList()); 193 } 194 195 /// 196 /// Methods 197 /// 198 199 /** 200 * Return a list of all the methods declared in this type declaration. 201 */ getDeclaredMethods()202 Set<ResolvedMethodDeclaration> getDeclaredMethods(); 203 204 /** 205 * Return a list of all the methods declared of this type declaration, either declared or inherited. 206 * Note that it should not include overridden methods. 207 */ getAllMethods()208 Set<MethodUsage> getAllMethods(); 209 210 /// 211 /// Assignability 212 /// 213 214 /** 215 * Can we assign instances of the given type to variables having the type defined 216 * by this declaration? 217 */ isAssignableBy(ResolvedType type)218 boolean isAssignableBy(ResolvedType type); 219 220 /** 221 * Can we assign instances of the type defined by this declaration to variables having the type defined 222 * by the given type? 223 */ canBeAssignedTo(ResolvedReferenceTypeDeclaration other)224 default boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { 225 return other.isAssignableBy(this); 226 } 227 228 /** 229 * Can we assign instances of the given type to variables having the type defined 230 * by this declaration? 231 */ isAssignableBy(ResolvedReferenceTypeDeclaration other)232 boolean isAssignableBy(ResolvedReferenceTypeDeclaration other); 233 234 /// 235 /// Annotations 236 /// 237 238 /** 239 * Has the type at least one annotation declared having the specified qualified name? 240 */ hasDirectlyAnnotation(String qualifiedName)241 boolean hasDirectlyAnnotation(String qualifiedName); 242 243 /** 244 * Has the type at least one annotation declared or inherited having the specified qualified name? 245 */ hasAnnotation(String qualifiedName)246 default boolean hasAnnotation(String qualifiedName) { 247 if (hasDirectlyAnnotation(qualifiedName)) { 248 return true; 249 } 250 return getAllAncestors().stream().anyMatch(it -> it.asReferenceType().getTypeDeclaration().hasDirectlyAnnotation(qualifiedName)); 251 } 252 253 /** 254 * This means that the type has a functional method. Conceptually, a functional interface has exactly one abstract method. 255 * Typically these classes has the FunctionInterface annotation but this is not mandatory. 256 */ isFunctionalInterface()257 boolean isFunctionalInterface(); 258 259 /// 260 /// Type parameters 261 /// 262 263 @Override findTypeParameter(String name)264 default Optional<ResolvedTypeParameterDeclaration> findTypeParameter(String name) { 265 for (ResolvedTypeParameterDeclaration tp : this.getTypeParameters()) { 266 if (tp.getName().equals(name)) { 267 return Optional.of(tp); 268 } 269 } 270 if (this.containerType().isPresent()) { 271 return this.containerType().get().findTypeParameter(name); 272 } 273 return Optional.empty(); 274 } 275 getConstructors()276 List<ResolvedConstructorDeclaration> getConstructors(); 277 } 278