• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&lt;String&gt; {}
62      * <p>
63      * In this case the ancestor is Comparable&lt;String&gt;
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