26
26
27
27
import com .google .common .base .Equivalence ;
28
28
import com .google .common .base .Optional ;
29
+ import com .google .common .base .Preconditions ;
29
30
import com .google .common .collect .ImmutableList ;
30
31
import com .google .common .collect .ImmutableSet ;
31
32
import java .util .HashSet ;
@@ -88,13 +89,13 @@ public String toString() {
88
89
* may be preferred in a number of cases:
89
90
*
90
91
* <ul>
91
- * <li>If you don't have an instance of {@code Types}.
92
- * <li>If you want a reliable {@code hashCode()} for the types, for example to construct a set
93
- * of types using {@link java.util.HashSet} with {@link Equivalence#wrap(Object)}.
94
- * <li>If you want distinct type variables to be considered equal if they have the same names
95
- * and bounds.
96
- * <li>If you want wildcard types to compare equal if they have the same bounds. {@code
97
- * Types.isSameType} never considers wildcards equal, even when comparing a type to itself.
92
+ * <li>If you don't have an instance of {@code Types}.
93
+ * <li>If you want a reliable {@code hashCode()} for the types, for example to construct a set
94
+ * of types using {@link java.util.HashSet} with {@link Equivalence#wrap(Object)}.
95
+ * <li>If you want distinct type variables to be considered equal if they have the same names
96
+ * and bounds.
97
+ * <li>If you want wildcard types to compare equal if they have the same bounds. {@code
98
+ * Types.isSameType} never considers wildcards equal, even when comparing a type to itself.
98
99
* </ul>
99
100
*/
100
101
public static Equivalence <TypeMirror > equivalence () {
@@ -347,10 +348,10 @@ private static boolean equal(
347
348
348
349
/**
349
350
* Returns the type of the innermost enclosing instance, or null if there is none. This is the
350
- * same as {@link DeclaredType#getEnclosingType()} except that it returns null rather than
351
- * NoType for a static type. We need this because of
352
- * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=508222">this bug</a> whereby
353
- * the Eclipse compiler returns a value for static classes that is not NoType.
351
+ * same as {@link DeclaredType#getEnclosingType()} except that it returns null rather than NoType
352
+ * for a static type. We need this because of <a
353
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=508222">this bug</a> whereby the Eclipse
354
+ * compiler returns a value for static classes that is not NoType.
354
355
*/
355
356
private static @ Nullable TypeMirror enclosingType (DeclaredType t ) {
356
357
TypeMirror enclosing = t .getEnclosingType ();
@@ -836,42 +837,121 @@ public Boolean visitDeclared(DeclaredType type, Void ignored) {
836
837
}
837
838
838
839
/**
839
- * Returns true if the raw type underlying the given {@link TypeMirror} represents the same raw
840
- * type as the given {@link Class} and throws an IllegalArgumentException if the {@link
841
- * TypeMirror} does not represent a type that can be referenced by a {@link Class}
840
+ * Returns {@code true} iff the raw type underlying the given {@link Class} represents the raw
841
+ * type of the given {@link TypeMirror} and throws an {@link IllegalArgumentException} if the
842
+ * {@link TypeMirror} does not represent a type that can be referenced by a {@link Class}.
843
+ *
844
+ * <p>Note: The representation need not be exact. For example, {@linkplain java.util.ArrayList}
845
+ * represents {@linkplain List}.
842
846
*/
843
847
public static boolean isTypeOf (final Class <?> clazz , TypeMirror type ) {
844
- checkNotNull (clazz );
845
- return type .accept (new IsTypeOf (clazz ), null );
848
+ return type .accept (new isTypeOf (clazz ), null );
846
849
}
847
850
848
- private static final class IsTypeOf extends SimpleTypeVisitor8 <Boolean , Void > {
851
+ private static final class isTypeOf extends SimpleTypeVisitor8 <Boolean , Void > {
849
852
private final Class <?> clazz ;
850
853
851
- IsTypeOf (Class <?> clazz ) {
852
- this .clazz = clazz ;
854
+ isTypeOf (Class <?> clazz ) {
855
+ this .clazz = Preconditions . checkNotNull ( clazz ) ;
853
856
}
854
857
855
858
@ Override
856
- protected Boolean defaultAction (TypeMirror type , Void ignored ) {
859
+ protected Boolean defaultAction (TypeMirror type , Void ignore ) {
860
+ return isExactTypeOf (clazz , type );
861
+ }
862
+
863
+ @ Override
864
+ public Boolean visitArray (ArrayType array , Void ignore ) {
865
+ return clazz .isArray () && isTypeOf (clazz .getComponentType (), array .getComponentType ());
866
+ }
867
+
868
+ @ Override
869
+ public Boolean visitDeclared (DeclaredType type , Void ignore ) {
870
+ return isDeclaredTypeOf (clazz , type );
871
+ }
872
+
873
+ @ Override
874
+ public Boolean visitTypeVariable (TypeVariable type , Void ignore ) {
875
+ TypeMirror upperBoundType = type .getUpperBound ();
876
+ if (upperBoundType .getKind () != TypeKind .INTERSECTION ) {
877
+ return isTypeOf (clazz , upperBoundType );
878
+ }
879
+
880
+ for (TypeMirror UBType : ((IntersectionType ) upperBoundType ).getBounds ()) {
881
+ if (isTypeOf (clazz , UBType )) {
882
+ return true ;
883
+ }
884
+ }
885
+
886
+ return false ;
887
+ }
888
+
889
+ @ Override
890
+ public Boolean visitWildcard (WildcardType type , Void ignore ) {
891
+ TypeMirror upperBoundType = type .getExtendsBound ();
892
+ return upperBoundType == null || isTypeOf (clazz , upperBoundType );
893
+ }
894
+ }
895
+
896
+ private static boolean isDeclaredTypeOf (final Class <?> clazz , DeclaredType declaredType ) {
897
+ if (isExactTypeOf (clazz , declaredType )) {
898
+ return true ;
899
+ }
900
+
901
+ TypeElement typeElement = MoreElements .asType (declaredType .asElement ());
902
+
903
+ for (TypeMirror i : typeElement .getInterfaces ()) {
904
+ if (isDeclaredTypeOf (clazz , MoreTypes .asDeclared (i ))) {
905
+ return true ;
906
+ }
907
+ }
908
+
909
+ /* For interfaces (including annotation types),
910
+ * and java.lang.Object, TypeElement#getSuperclass() returns
911
+ * NoType with the NONE kind.
912
+ */
913
+ TypeMirror superClassType = typeElement .getSuperclass ();
914
+ return (superClassType .getKind () != TypeKind .NONE )
915
+ && isDeclaredTypeOf (clazz , MoreTypes .asDeclared (superClassType ));
916
+ }
917
+
918
+ /**
919
+ * Returns {@code true} iff the raw type underlying the given {@link TypeMirror} represents the
920
+ * same raw type as the given {@link Class} and throws an {@link IllegalArgumentException} if the
921
+ * {@link TypeMirror} does not represent a type that can be referenced by a {@link Class}
922
+ */
923
+ public static boolean isExactTypeOf (final Class <?> clazz , TypeMirror type ) {
924
+ return type .accept (new isExactTypeOf (clazz ), null );
925
+ }
926
+
927
+ private static final class isExactTypeOf extends SimpleTypeVisitor8 <Boolean , Void > {
928
+ private final Class <?> clazz ;
929
+
930
+ isExactTypeOf (Class <?> clazz ) {
931
+ this .clazz = Preconditions .checkNotNull (clazz );
932
+ }
933
+
934
+ @ Override
935
+ protected Boolean defaultAction (TypeMirror type , Void ignore ) {
857
936
throw new IllegalArgumentException (type + " cannot be represented as a Class<?>." );
858
937
}
859
938
860
939
@ Override
861
- public Boolean visitNoType (NoType noType , Void p ) {
862
- if (noType .getKind (). equals ( TypeKind .VOID ) ) {
940
+ public Boolean visitNoType (NoType noType , Void ignore ) {
941
+ if (noType .getKind () == TypeKind .VOID ) {
863
942
return clazz .equals (Void .TYPE );
864
943
}
944
+
865
945
throw new IllegalArgumentException (noType + " cannot be represented as a Class<?>." );
866
946
}
867
947
868
948
@ Override
869
- public Boolean visitError (ErrorType errorType , Void p ) {
949
+ public Boolean visitError (ErrorType errorType , Void ignore ) {
870
950
return false ;
871
951
}
872
952
873
953
@ Override
874
- public Boolean visitPrimitive (PrimitiveType type , Void p ) {
954
+ public Boolean visitPrimitive (PrimitiveType type , Void ignore ) {
875
955
switch (type .getKind ()) {
876
956
case BOOLEAN :
877
957
return clazz .equals (Boolean .TYPE );
@@ -895,12 +975,12 @@ public Boolean visitPrimitive(PrimitiveType type, Void p) {
895
975
}
896
976
897
977
@ Override
898
- public Boolean visitArray (ArrayType array , Void p ) {
899
- return clazz .isArray () && isTypeOf (clazz .getComponentType (), array .getComponentType ());
978
+ public Boolean visitArray (ArrayType array , Void ignore ) {
979
+ return clazz .isArray () && isExactTypeOf (clazz .getComponentType (), array .getComponentType ());
900
980
}
901
981
902
982
@ Override
903
- public Boolean visitDeclared (DeclaredType type , Void ignored ) {
983
+ public Boolean visitDeclared (DeclaredType type , Void ignore ) {
904
984
TypeElement typeElement = MoreElements .asType (type .asElement ());
905
985
return typeElement .getQualifiedName ().contentEquals (clazz .getCanonicalName ());
906
986
}
@@ -946,8 +1026,8 @@ private static boolean isObjectType(DeclaredType type) {
946
1026
/**
947
1027
* Resolves a {@link VariableElement} parameter to a method or constructor based on the given
948
1028
* container, or a member of a class. For parameters to a method or constructor, the variable's
949
- * enclosing element must be a supertype of the container type. For example, given a
950
- * {@code container} of type {@code Set<String>}, and a variable corresponding to the {@code E e}
1029
+ * enclosing element must be a supertype of the container type. For example, given a {@code
1030
+ * container} of type {@code Set<String>}, and a variable corresponding to the {@code E e}
951
1031
* parameter in the {@code Set.add(E e)} method, this will return a TypeMirror for {@code String}.
952
1032
*/
953
1033
public static TypeMirror asMemberOf (
0 commit comments