1 | /* |
---|---|
2 | * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser. |
3 | * Copyright (C) 2011, 2013-2020 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.types; |
23 | |
24 | import java.util.ArrayList; |
25 | import java.util.Collections; |
26 | import java.util.LinkedList; |
27 | import java.util.List; |
28 | import java.util.Map; |
29 | import java.util.Optional; |
30 | import java.util.Set; |
31 | import java.util.stream.Collectors; |
32 | |
33 | import com.github.javaparser.ast.AccessSpecifier; |
34 | import com.github.javaparser.resolution.MethodUsage; |
35 | import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration; |
36 | import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; |
37 | import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; |
38 | import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; |
39 | import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration.Bound; |
40 | import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParameterValueProvider; |
41 | import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametersMap; |
42 | import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametrized; |
43 | import com.github.javaparser.utils.Pair; |
44 | |
45 | /** |
46 | * A ReferenceType like a class, an interface or an enum. Note that this type can contain also the values |
47 | * specified for the type parameters. |
48 | * |
49 | * @author Federico Tomassetti |
50 | */ |
51 | public abstract class ResolvedReferenceType implements ResolvedType, |
52 | ResolvedTypeParametrized, ResolvedTypeParameterValueProvider { |
53 | |
54 | // |
55 | // Fields |
56 | // |
57 | |
58 | protected ResolvedReferenceTypeDeclaration typeDeclaration; |
59 | protected ResolvedTypeParametersMap typeParametersMap; |
60 | |
61 | // |
62 | // Constructors |
63 | // |
64 | |
65 | public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration) { |
66 | this(typeDeclaration, deriveParams(typeDeclaration)); |
67 | } |
68 | |
69 | public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeArguments) { |
70 | if (typeDeclaration == null) { |
71 | throw new IllegalArgumentException("TypeDeclaration is not expected to be null"); |
72 | } |
73 | if (typeDeclaration.isTypeParameter()) { |
74 | throw new IllegalArgumentException("You should use only Classes, Interfaces and enums"); |
75 | } |
76 | if (typeArguments.size() > 0 && typeArguments.size() != typeDeclaration.getTypeParameters().size()) { |
77 | throw new IllegalArgumentException(String.format( |
78 | "expected either zero type arguments or has many as defined in the declaration (%d). Found %d", |
79 | typeDeclaration.getTypeParameters().size(), typeArguments.size())); |
80 | } |
81 | ResolvedTypeParametersMap.Builder typeParametersMapBuilder = new ResolvedTypeParametersMap.Builder(); |
82 | for (int i = 0; i < typeArguments.size(); i++) { |
83 | typeParametersMapBuilder.setValue(typeDeclaration.getTypeParameters().get(i), typeArguments.get(i)); |
84 | } |
85 | this.typeParametersMap = typeParametersMapBuilder.build(); |
86 | this.typeDeclaration = typeDeclaration; |
87 | } |
88 | |
89 | // |
90 | // Public Object methods |
91 | // |
92 | |
93 | @Override |
94 | public boolean equals(Object o) { |
95 | if (this == o) return true; |
96 | if (o == null || getClass() != o.getClass()) return false; |
97 | |
98 | ResolvedReferenceType that = (ResolvedReferenceType) o; |
99 | |
100 | if (!typeDeclaration.equals(that.typeDeclaration)) return false; |
101 | if (!typeParametersMap.equals(that.typeParametersMap)) return false; |
102 | |
103 | return true; |
104 | } |
105 | |
106 | @Override |
107 | public int hashCode() { |
108 | int result = typeDeclaration.hashCode(); |
109 | result = 31 * result + typeParametersMap.hashCode(); |
110 | return result; |
111 | } |
112 | |
113 | @Override |
114 | public String toString() { |
115 | return "ReferenceType{" + getQualifiedName() + |
116 | ", typeParametersMap=" + typeParametersMap + |
117 | '}'; |
118 | } |
119 | |
120 | /// |
121 | /// Relation with other types |
122 | /// |
123 | |
124 | @Override |
125 | public final boolean isReferenceType() { |
126 | return true; |
127 | } |
128 | |
129 | /// |
130 | /// Downcasting |
131 | /// |
132 | |
133 | @Override |
134 | public ResolvedReferenceType asReferenceType() { |
135 | return this; |
136 | } |
137 | |
138 | /// |
139 | /// Naming |
140 | /// |
141 | |
142 | @Override |
143 | public String describe() { |
144 | StringBuilder sb = new StringBuilder(); |
145 | if (hasName()) { |
146 | sb.append(typeDeclaration.getQualifiedName()); |
147 | } else { |
148 | sb.append("<anonymous class>"); |
149 | } |
150 | if (!typeParametersMap().isEmpty()) { |
151 | sb.append("<"); |
152 | sb.append(String.join(", ", typeDeclaration.getTypeParameters().stream() |
153 | .map(tp -> typeParametersMap().getValue(tp).describe()) |
154 | .collect(Collectors.toList()))); |
155 | sb.append(">"); |
156 | } |
157 | return sb.toString(); |
158 | } |
159 | |
160 | /// |
161 | /// TypeParameters |
162 | /// |
163 | |
164 | /** |
165 | * Execute a transformation on all the type parameters of this element. |
166 | */ |
167 | public abstract ResolvedType transformTypeParameters(ResolvedTypeTransformer transformer); |
168 | |
169 | @Override |
170 | public ResolvedType replaceTypeVariables(ResolvedTypeParameterDeclaration tpToReplace, ResolvedType replaced, |
171 | Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes) { |
172 | if (replaced == null) { |
173 | throw new IllegalArgumentException(); |
174 | } |
175 | |
176 | ResolvedReferenceType result = this; |
177 | int i = 0; |
178 | for (ResolvedType tp : this.typeParametersValues()) { |
179 | ResolvedType transformedTp = tp.replaceTypeVariables(tpToReplace, replaced, inferredTypes); |
180 | // Identity comparison on purpose |
181 | if (tp.isTypeVariable() && tp.asTypeVariable().describe().equals(tpToReplace.getName())) { |
182 | inferredTypes.put(tp.asTypeParameter(), replaced); |
183 | } |
184 | // FIXME |
185 | if (true) { |
186 | List<ResolvedType> typeParametersCorrected = result.asReferenceType().typeParametersValues(); |
187 | typeParametersCorrected.set(i, transformedTp); |
188 | result = create(typeDeclaration, typeParametersCorrected); |
189 | } |
190 | i++; |
191 | } |
192 | |
193 | List<ResolvedType> values = result.typeParametersValues(); |
194 | // FIXME |
195 | if (values.contains(tpToReplace)) { |
196 | int index = values.indexOf(tpToReplace); |
197 | values.set(index, replaced); |
198 | if(result.getTypeDeclaration().isPresent()) { |
199 | return create(result.getTypeDeclaration().get(), values); |
200 | } |
201 | } |
202 | |
203 | return result; |
204 | } |
205 | |
206 | /// |
207 | /// Assignability |
208 | /// |
209 | |
210 | /** |
211 | * This method checks if ThisType t = new OtherType() would compile. |
212 | */ |
213 | @Override |
214 | public abstract boolean isAssignableBy(ResolvedType other); |
215 | |
216 | /// |
217 | /// Ancestors |
218 | /// |
219 | |
220 | /** |
221 | * Return all ancestors, that means all superclasses and interfaces. |
222 | * This list should always include Object (unless this is a reference to Object). |
223 | * The type typeParametersValues should be expressed in terms of this type typeParametersValues. |
224 | * <p> |
225 | * For example, given: |
226 | * <p> |
227 | * class Foo<A, B> {} |
228 | * class Bar<C> extends Foo<C, String> {} |
229 | * <p> |
230 | * a call to getAllAncestors on a reference to Bar having type parameter Boolean should include |
231 | * Foo<Boolean, String>. |
232 | */ |
233 | public abstract List<ResolvedReferenceType> getAllAncestors(); |
234 | |
235 | /** |
236 | * Return direct ancestors, that means the superclasses and interfaces implemented directly. |
237 | * This list should include Object if the class has no other superclass or the interface is not extending another interface. |
238 | * There is an exception for Object itself. |
239 | */ |
240 | public abstract List<ResolvedReferenceType> getDirectAncestors(); |
241 | |
242 | public final List<ResolvedReferenceType> getAllInterfacesAncestors() { |
243 | return getAllAncestors().stream() |
244 | .filter(it -> it.getTypeDeclaration().isPresent()) |
245 | .filter(it -> it.getTypeDeclaration().get().isInterface()) |
246 | .collect(Collectors.toList()); |
247 | } |
248 | |
249 | public final List<ResolvedReferenceType> getAllClassesAncestors() { |
250 | return getAllAncestors().stream() |
251 | .filter(it -> it.getTypeDeclaration().isPresent()) |
252 | .filter(it -> it.getTypeDeclaration().get().isClass()) |
253 | .collect(Collectors.toList()); |
254 | } |
255 | |
256 | /// |
257 | /// Type parameters |
258 | /// |
259 | |
260 | /** |
261 | * Get the type associated with the type parameter with the given name. |
262 | * It returns Optional.empty unless the type declaration declares a type parameter with the given name. |
263 | */ |
264 | public Optional<ResolvedType> getGenericParameterByName(String name) { |
265 | for (ResolvedTypeParameterDeclaration tp : typeDeclaration.getTypeParameters()) { |
266 | if (tp.getName().equals(name)) { |
267 | return Optional.of(this.typeParametersMap().getValue(tp)); |
268 | } |
269 | } |
270 | return Optional.empty(); |
271 | } |
272 | |
273 | /** |
274 | * Get the values for all type parameters declared on this type. |
275 | * The list can be empty for raw types. |
276 | */ |
277 | public List<ResolvedType> typeParametersValues() { |
278 | return this.typeParametersMap.isEmpty() ? Collections.emptyList() : typeDeclaration.getTypeParameters().stream().map(tp -> typeParametersMap.getValue(tp)).collect(Collectors.toList()); |
279 | } |
280 | |
281 | /** |
282 | * Get the values for all type parameters declared on this type. |
283 | * In case of raw types the values correspond to TypeVariables. |
284 | */ |
285 | public List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> getTypeParametersMap() { |
286 | List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> typeParametersMap = new ArrayList<>(); |
287 | if (!isRawType()) { |
288 | for (int i = 0; i < typeDeclaration.getTypeParameters().size(); i++) { |
289 | typeParametersMap.add(new Pair<>(typeDeclaration.getTypeParameters().get(i), typeParametersValues().get(i))); |
290 | } |
291 | } |
292 | return typeParametersMap; |
293 | } |
294 | |
295 | @Override |
296 | public ResolvedTypeParametersMap typeParametersMap() { |
297 | return typeParametersMap; |
298 | } |
299 | |
300 | /// |
301 | /// Other methods introduced by ReferenceType |
302 | /// |
303 | |
304 | /** |
305 | * Corresponding TypeDeclaration |
306 | */ |
307 | public final Optional<ResolvedReferenceTypeDeclaration> getTypeDeclaration() { |
308 | return Optional.of(typeDeclaration); |
309 | } |
310 | |
311 | /** |
312 | * The type of the field could be different from the one in the corresponding FieldDeclaration because |
313 | * type variables would be solved. |
314 | */ |
315 | public Optional<ResolvedType> getFieldType(String name) { |
316 | if (!typeDeclaration.hasField(name)) { |
317 | return Optional.empty(); |
318 | } |
319 | ResolvedType type = typeDeclaration.getField(name).getType(); |
320 | type = useThisTypeParametersOnTheGivenType(type); |
321 | return Optional.of(type); |
322 | } |
323 | |
324 | /** |
325 | * Has the TypeDeclaration a name? Anonymous classes do not have one. |
326 | */ |
327 | public boolean hasName() { |
328 | return typeDeclaration.hasName(); |
329 | } |
330 | |
331 | /** |
332 | * Qualified name of the declaration. |
333 | */ |
334 | public String getQualifiedName() { |
335 | return typeDeclaration.getQualifiedName(); |
336 | } |
337 | |
338 | /** |
339 | * Id of the declaration. It corresponds to the qualified name, unless for local classes. |
340 | */ |
341 | public String getId() { |
342 | return typeDeclaration.getId(); |
343 | } |
344 | |
345 | /** |
346 | * Methods declared on this type. |
347 | */ |
348 | public abstract Set<MethodUsage> getDeclaredMethods(); |
349 | |
350 | /** |
351 | * Fields declared on this type. |
352 | */ |
353 | public abstract Set<ResolvedFieldDeclaration> getDeclaredFields(); |
354 | |
355 | public boolean isRawType() { |
356 | if (!typeDeclaration.getTypeParameters().isEmpty()) { |
357 | if (typeParametersMap().isEmpty()) { |
358 | return true; |
359 | } |
360 | for (String name : typeParametersMap().getNames()) { |
361 | Optional<ResolvedType> value = typeParametersMap().getValueBySignature(name); |
362 | if (!value.isPresent() || !value.get().isTypeVariable() || !value.get().asTypeVariable().qualifiedName().equals(name)) { |
363 | return false; |
364 | } |
365 | } |
366 | return true; |
367 | } |
368 | return false; |
369 | } |
370 | |
371 | public Optional<ResolvedType> typeParamValue(ResolvedTypeParameterDeclaration typeParameterDeclaration) { |
372 | if (typeParameterDeclaration.declaredOnMethod()) { |
373 | throw new IllegalArgumentException(); |
374 | } |
375 | if(!this.getTypeDeclaration().isPresent()) { |
376 | return Optional.empty(); // TODO: Consider IllegalStateException or similar |
377 | } |
378 | |
379 | String typeId = this.getTypeDeclaration().get().getId(); |
380 | if (typeId.equals(typeParameterDeclaration.getContainerId())) { |
381 | return Optional.of(this.typeParametersMap().getValue(typeParameterDeclaration)); |
382 | } |
383 | for (ResolvedReferenceType ancestor : this.getAllAncestors()) { |
384 | if (ancestor.getId().equals(typeParameterDeclaration.getContainerId())) { |
385 | return Optional.of(ancestor.typeParametersMap().getValue(typeParameterDeclaration)); |
386 | } |
387 | } |
388 | return Optional.empty(); |
389 | } |
390 | |
391 | public abstract ResolvedType toRawType(); |
392 | |
393 | /** |
394 | * Get a list of all the methods available on this type. This list includes methods declared in this type and |
395 | * methods inherited. This list includes methods of all sort of visibility. However it does not include methods |
396 | * that have been overwritten. |
397 | */ |
398 | public List<ResolvedMethodDeclaration> getAllMethods() { |
399 | if(!this.getTypeDeclaration().isPresent()) { |
400 | return new ArrayList<>(); // empty list -- consider IllegalStateException or similar |
401 | } |
402 | |
403 | // Get the methods declared directly on this. |
404 | List<ResolvedMethodDeclaration> allMethods = new LinkedList<>( |
405 | this.getTypeDeclaration().get().getDeclaredMethods() |
406 | ); |
407 | // Also get methods inherited from ancestors. |
408 | getDirectAncestors().forEach(a -> allMethods.addAll(a.getAllMethods())); |
409 | |
410 | return allMethods; |
411 | } |
412 | |
413 | /** |
414 | * Fields which are visible to inheritors. They include all inherited fields which are visible to this |
415 | * type plus all declared fields which are not private. |
416 | */ |
417 | public List<ResolvedFieldDeclaration> getAllFieldsVisibleToInheritors() { |
418 | List<ResolvedFieldDeclaration> res = new LinkedList<>(this.getDeclaredFields().stream() |
419 | .filter(f -> f.accessSpecifier() != AccessSpecifier.PRIVATE) |
420 | .collect(Collectors.toList())); |
421 | |
422 | getDirectAncestors().forEach(a -> |
423 | res.addAll(a.getAllFieldsVisibleToInheritors())); |
424 | |
425 | return res; |
426 | } |
427 | |
428 | public List<ResolvedMethodDeclaration> getAllMethodsVisibleToInheritors() { |
429 | return this.getAllMethods().stream() |
430 | .filter(m -> m.accessSpecifier() != AccessSpecifier.PRIVATE) |
431 | .collect(Collectors.toList()); |
432 | } |
433 | |
434 | // |
435 | // Protected methods |
436 | // |
437 | |
438 | protected abstract ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeParameters); |
439 | |
440 | protected ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, ResolvedTypeParametersMap typeParametersMap) { |
441 | return create(typeDeclaration, typeDeclaration.getTypeParameters().stream() |
442 | .map(typeParametersMap::getValue) |
443 | .collect(Collectors.toList())); |
444 | } |
445 | |
446 | protected abstract ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration); |
447 | |
448 | protected boolean isCorrespondingBoxingType(String typeName) { |
449 | switch (typeName) { |
450 | case "boolean": |
451 | return getQualifiedName().equals(Boolean.class.getCanonicalName()); |
452 | case "char": |
453 | return getQualifiedName().equals(Character.class.getCanonicalName()); |
454 | case "byte": |
455 | return getQualifiedName().equals(Byte.class.getCanonicalName()); |
456 | case "short": |
457 | return getQualifiedName().equals(Short.class.getCanonicalName()); |
458 | case "int": |
459 | return getQualifiedName().equals(Integer.class.getCanonicalName()); |
460 | case "long": |
461 | return getQualifiedName().equals(Long.class.getCanonicalName()); |
462 | case "float": |
463 | return getQualifiedName().equals(Float.class.getCanonicalName()); |
464 | case "double": |
465 | return getQualifiedName().equals(Double.class.getCanonicalName()); |
466 | default: |
467 | throw new UnsupportedOperationException(typeName); |
468 | } |
469 | } |
470 | |
471 | protected boolean compareConsideringTypeParameters(ResolvedReferenceType other) { |
472 | if (other.equals(this)) { |
473 | return true; |
474 | } |
475 | if (this.getQualifiedName().equals(other.getQualifiedName())) { |
476 | if (this.isRawType() || other.isRawType()) { |
477 | return true; |
478 | } |
479 | List<ResolvedType> typeParametersValues = typeParametersValues(); |
480 | if (typeParametersValues.size() != other.typeParametersValues().size()) { |
481 | throw new IllegalStateException(); |
482 | } |
483 | for (int i = 0; i < typeParametersValues.size(); i++) { |
484 | ResolvedType thisParam = typeParametersValues.get(i); |
485 | ResolvedType otherParam = other.typeParametersValues().get(i); |
486 | if (!thisParam.equals(otherParam)) { |
487 | if (thisParam instanceof ResolvedWildcard) { |
488 | ResolvedWildcard thisParamAsWildcard = (ResolvedWildcard) thisParam; |
489 | if (thisParamAsWildcard.isSuper() && otherParam.isAssignableBy(thisParamAsWildcard.getBoundedType())) { |
490 | // ok |
491 | } else if (thisParamAsWildcard.isExtends() && thisParamAsWildcard.getBoundedType().isAssignableBy(otherParam)) { |
492 | // ok |
493 | } else if (!thisParamAsWildcard.isBounded()) { |
494 | // ok |
495 | } else { |
496 | return false; |
497 | } |
498 | } else { |
499 | if (thisParam instanceof ResolvedTypeVariable && otherParam instanceof ResolvedTypeVariable) { |
500 | List<ResolvedType> thisBounds = thisParam.asTypeVariable().asTypeParameter().getBounds() |
501 | .stream().map(ResolvedTypeParameterDeclaration.Bound::getType) |
502 | .collect(Collectors.toList()); |
503 | List<ResolvedType> otherBounds = otherParam.asTypeVariable().asTypeParameter().getBounds() |
504 | .stream().map(ResolvedTypeParameterDeclaration.Bound::getType) |
505 | .collect(Collectors.toList()); |
506 | return thisBounds.size() == otherBounds.size() && otherBounds.containsAll(thisBounds); |
507 | } else if (!(thisParam instanceof ResolvedTypeVariable) && otherParam instanceof ResolvedTypeVariable) { |
508 | return compareConsideringVariableTypeParameters(thisParam, (ResolvedTypeVariable)otherParam); |
509 | } else if (thisParam instanceof ResolvedTypeVariable && !(otherParam instanceof ResolvedTypeVariable)) { |
510 | return compareConsideringVariableTypeParameters(otherParam, (ResolvedTypeVariable) thisParam); |
511 | } |
512 | return false; |
513 | } |
514 | } |
515 | } |
516 | return true; |
517 | } |
518 | return false; |
519 | } |
520 | |
521 | // |
522 | // Private methods |
523 | // |
524 | |
525 | private boolean compareConsideringVariableTypeParameters(ResolvedType referenceType, ResolvedTypeVariable typeVariable) { |
526 | // verify if the ResolvedTypeVariable has only one type variable and the bound is |
527 | // not a reference type with a bound parameter |
528 | // for example EnumSet<E> noneOf(Class<E> elementType) |
529 | List<Bound> bounds = typeVariable.asTypeVariable().asTypeParameter().getBounds(); |
530 | if (bounds.size() == 1) { |
531 | ResolvedType boundType = bounds.get(0).getType(); |
532 | boolean hasTypeParameter = boundType.isReferenceType() |
533 | && !boundType.asReferenceType().typeParametersMap.isEmpty(); |
534 | return hasTypeParameter |
535 | ? compareConsideringTypeParameters(boundType.asReferenceType()) |
536 | : boundType.isAssignableBy(referenceType); |
537 | } |
538 | return false; |
539 | } |
540 | |
541 | private static List<ResolvedType> deriveParams(ResolvedReferenceTypeDeclaration typeDeclaration) { |
542 | if (typeDeclaration == null) { |
543 | throw new IllegalArgumentException("TypeDeclaration is not expected to be null"); |
544 | } |
545 | List<ResolvedTypeParameterDeclaration> typeParameters = typeDeclaration.getTypeParameters(); |
546 | if (typeParameters == null) { |
547 | throw new RuntimeException("Type parameters are not expected to be null"); |
548 | } |
549 | return typeParameters.stream().map(ResolvedTypeVariable::new).collect(Collectors.toList()); |
550 | } |
551 | |
552 | public abstract ResolvedReferenceType deriveTypeParameters(ResolvedTypeParametersMap typeParametersMap); |
553 | |
554 | |
555 | /** |
556 | * We don't make this _ex_plicit in the data representation because that would affect codegen |
557 | * and make everything generate like {@code <T extends Object>} instead of {@code <T>} |
558 | * |
559 | * @return true, if this represents {@code java.lang.Object} |
560 | * @see ResolvedReferenceTypeDeclaration#isJavaLangObject() |
561 | * @see <a href="https://github.com/javaparser/javaparser/issues/2044">https://github.com/javaparser/javaparser/issues/2044</a> |
562 | */ |
563 | public boolean isJavaLangObject() { |
564 | return this.isReferenceType() |
565 | && hasName() // Consider anonymous classes |
566 | && getQualifiedName().equals(java.lang.Object.class.getCanonicalName()); |
567 | } |
568 | |
569 | /** |
570 | * @return true, if this represents {@code java.lang.Enum} |
571 | * @see ResolvedReferenceTypeDeclaration#isJavaLangEnum() |
572 | */ |
573 | public boolean isJavaLangEnum() { |
574 | return this.isReferenceType() |
575 | && hasName() // Consider anonymous classes |
576 | && getQualifiedName().equals(java.lang.Enum.class.getCanonicalName()); |
577 | } |
578 | |
579 | } |
580 |
Members