@Test
  public void isSubtypeOf() throws Exception {
    JavaSymbol.PackageJavaSymbol packageSymbol =
        new JavaSymbol.PackageJavaSymbol("org.foo.bar", null);
    JavaSymbol.TypeJavaSymbol typeSymbol =
        new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, "MyType", packageSymbol);
    JavaSymbol.TypeVariableJavaSymbol typeVariableSymbol =
        new JavaSymbol.TypeVariableJavaSymbol("T", typeSymbol);
    ClassJavaType classType = (ClassJavaType) typeSymbol.type;
    TypeVariableJavaType typeVariableType = (TypeVariableJavaType) typeVariableSymbol.type;
    ArrayJavaType arrayType = new ArrayJavaType(typeSymbol.type, symbols.arrayClass);
    typeVariableType.bounds = Lists.newArrayList(symbols.objectType);

    classType.supertype = symbols.objectType;
    classType.interfaces = Lists.newArrayList(symbols.cloneableType);
    assertThat(classType.isSubtypeOf("java.lang.Object")).isTrue();
    assertThat(classType.isSubtypeOf(symbols.objectType)).isTrue();

    assertThat(classType.isSubtypeOf("org.foo.bar.MyType")).isTrue();
    assertThat(classType.isSubtypeOf(typeSymbol.type)).isTrue();

    assertThat(classType.isSubtypeOf("java.lang.CharSequence")).isFalse();
    assertThat(classType.isSubtypeOf(symbols.stringType)).isFalse();

    assertThat(classType.isSubtypeOf("java.lang.Cloneable")).isTrue();
    assertThat(classType.isSubtypeOf(symbols.cloneableType)).isTrue();
    assertThat(new JavaType(JavaType.BYTE, null).isSubtypeOf("java.lang.Object")).isFalse();

    assertThat(arrayType.isSubtypeOf("org.foo.bar.MyType[]")).isTrue();
    assertThat(arrayType.isSubtypeOf(new ArrayJavaType(typeSymbol.type, symbols.arrayClass)))
        .isTrue();

    assertThat(arrayType.isSubtypeOf("org.foo.bar.MyType")).isFalse();
    assertThat(arrayType.isSubtypeOf(typeSymbol.type)).isFalse();

    assertThat(arrayType.isSubtypeOf("java.lang.Object[]")).isTrue();
    assertThat(arrayType.isSubtypeOf(new ArrayJavaType(symbols.objectType, symbols.arrayClass)))
        .isTrue();

    assertThat(arrayType.isSubtypeOf("java.lang.Object")).isTrue();
    assertThat(arrayType.isSubtypeOf(symbols.objectType)).isTrue();

    assertThat(symbols.nullType.isSubtypeOf(symbols.objectType)).isTrue();
    assertThat(symbols.nullType.isSubtypeOf("java.lang.Object")).isTrue();
    assertThat(symbols.objectType.isSubtypeOf(symbols.nullType)).isFalse();

    assertThat(symbols.nullType.isSubtypeOf(arrayType)).isTrue();
    assertThat(arrayType.isSubtypeOf(symbols.nullType)).isFalse();
    assertThat(symbols.nullType.isSubtypeOf(symbols.nullType)).isTrue();

    assertThat(arrayType.isSubtypeOf("org.foo.bar.SomeClass[]")).isFalse();

    assertThat(typeVariableType.isSubtypeOf("java.lang.Object")).isTrue();
    assertThat(typeVariableType.is("java.lang.Object")).isFalse();
    assertThat(typeVariableType.isSubtypeOf("java.lang.CharSequence")).isFalse();

    assertThat(Symbols.unknownType.is("java.lang.Object")).isFalse();
    assertThat(Symbols.unknownType.isSubtypeOf("java.lang.CharSequence")).isFalse();
    assertThat(Symbols.unknownType.isSubtypeOf(symbols.objectType)).isFalse();
  }
  @Test
  public void erasure_of_type_variable() {
    JavaSymbol.TypeJavaSymbol typeSymbol =
        new JavaSymbol.TypeJavaSymbol(
            Flags.PUBLIC, "MyType", new JavaSymbol.PackageJavaSymbol("org.foo.bar", null));
    TypeSubstitution typeSubstitution = new TypeSubstitution();
    typeSubstitution.add(
        (TypeVariableJavaType) new JavaSymbol.TypeVariableJavaSymbol("T", typeSymbol).type,
        typeSymbol.type);
    ParametrizedTypeJavaType parametrizedType =
        new ParametrizedTypeJavaType(typeSymbol, typeSubstitution);

    TypeVariableJavaType typeVariableType =
        (TypeVariableJavaType) new JavaSymbol.TypeVariableJavaSymbol("X", typeSymbol).type;
    typeVariableType.bounds = ImmutableList.<JavaType>of(parametrizedType);

    assertThat(typeVariableType.erasure()).isNotEqualTo(parametrizedType);
    assertThat(typeVariableType.erasure()).isEqualTo(parametrizedType.erasure());
  }