Class TypeAdaptor

java.lang.Object
spoon.support.adaption.TypeAdaptor

public class TypeAdaptor extends Object
Determines subtyping relationships and adapts generics from a super- to a subclass.
  • Constructor Details

    • TypeAdaptor

      public TypeAdaptor(CtType<?> hierarchyStart)
      Creates a new type adaptor using the given type as the start of its hierarchy.
      Parameters:
      hierarchyStart - the start of the hierarchy
    • TypeAdaptor

      public TypeAdaptor(CtTypeReference<?> hierarchyStart)
      Creates a new type adaptor using the given reference as the start of its hierarchy.
      Parameters:
      hierarchyStart - the start of the hierarchy
    • TypeAdaptor

      public TypeAdaptor(CtMethod<?> hierarchyStart)
      Creates a new type adaptor using the given method as the start of its hierarchy.
      Parameters:
      hierarchyStart - the start of the hierarchy
    • TypeAdaptor

      public TypeAdaptor(CtConstructor<?> hierarchyStart)
      Creates a new type adaptor using the given constructor as the start of its hierarchy.
      Parameters:
      hierarchyStart - the start of the hierarchy
  • Method Details

    • isSubtypeOf

      public boolean isSubtypeOf(CtTypeReference<?> superRef)
      Checks if the context of this type adapter is a subtype of the passed superRef.
      Parameters:
      superRef - the super reference to check against
      Returns:
      true if the context of this type adapter is a subtype of the passed superRef
      See Also:
      isSubtype(CtType, CtTypeReference)
    • getHierarchyStart

      public CtType<?> getHierarchyStart()
      Returns:
      the context of this type adaptor
    • isSubtype

      public static boolean isSubtype(CtType<?> base, CtTypeReference<?> superRef)
      Checks whether the base is a subtype of the passed superref. Generic parameters in superRef are ignored.
      Parameters:
      base - the base type
      superRef - the potential supertype
      Returns:
      true if base extends/implements the super type
    • adaptMethod

      public CtMethod<?> adaptMethod(CtMethod<?> inputMethod)
      Adapts a given method to the context of this type adapter. The parent of the method will be set to the context of this adapter.

      As an example: The method method in

      
        interface Parent<T, X> {
          <R> R method(T t, X x);
        }
       
      adapted to
      interface Child<Q> extends Parent<Q, String> {}
      would return
      <R> R method(Q t, String x);
      .
      Parameters:
      inputMethod - the method to adapt
      Returns:
      the input method but with the return type, parameter types and thrown types adapted to the context of this type adapter
    • isConflicting

      public boolean isConflicting(CtMethod<?> first, CtMethod<?> second)
      Checks if two given methods are conflicting, i.e. they can not both be declared in the same class. This happens if the erasure of the methods is the same or one overrides the other. This method is used to remove methods that were already visited or were overwritten/shadowed by a subclass in various places.
      Parameters:
      first - the first method
      second - the second method
      Returns:
      true if the methods are conflicting
    • isSameSignature

      public boolean isSameSignature(CtMethod<?> first, CtMethod<?> second)
      Checks if two methods have the same signature, once you adapt both to the context of this type adapter.
      Two methods, M and N, have the same signature if they have the same name, the same type parameters (if any) (ยง8.4.4), and, after adapting the formal parameter types of N to the type parameters of M, the same formal parameter types.

      Adapting both to the context of this adapter is needed when dealing with inherited methods:
      
         class TypeA {
           void foo(String bar);
         }
         interface IFoo<T> {
           void foo(T bar);
         }
         class Foo extends TypeA implements IFoo<String> {}
       

      Here TypeA#foo and IFoo#foo have the same signature if checked with Foo as the context. In fact, TypeA#foo actually implements the method from IFoo, even though it does not share any inheritance relation with it.

      Parameters:
      first - the first method
      second - the second method
      Returns:
      true if the two methods have the same signature
    • isOverriding

      public boolean isOverriding(CtMethod<?> subMethod, CtMethod<?> superMethod)
      Checks if subMethod overrides superMethod. A method overrides another, iff
      • They have the same name
      • They have the same amount of parameters
      • They are not static
      • The declaring type of subMethod is a subtype of the declaring type of superMethod
      • The erasure of the parameters is equal, after adapting the superMethod to the declaring type of subMethod. One needs to adapt the whole method here and can not just check the erasure of the adapted parameter types, as they might depend on formal type parameters declared on the method:
        
               class Foo<T> {
                 <F extends T> void foo(F t);
               }
               class Sub<R extends String> extends Foo<R> {
                 <Q extends R> void foo(Q t);
               }
             
        If we did not adapt the whole method, we would not have a corresponding formal parameter declaration with the correct upper bound we can adapt to and would erase to Object instead.
      Parameters:
      subMethod - the method that might override the other
      superMethod - the method that might be overridden
      Returns:
      true if subMethod overrides superMethod
    • adaptType

      public CtTypeReference<?> adaptType(CtTypeReference<?> superRef)
      Adapts a type from a supertype to the context of this adaptor. In essence, this method builds the inheritance hierarchy from its context to the super reference (with some smarts to figure out what to do if superRef is actually a type parameter) and then walks backwards along that chain until it finds a type variable in the adaptor's context or a terminating type.

      For example:

      
         interface Top<T, S> {}
         interface Middle<Q> extends Top<Q, String> {}
         interface Bottom<R> extends Middle<R> {}
       
      If you adapt T from Top to Middle you get Q. If you adapt T from Top to Bottom you get R.
      If you adapt S from Top to Middle/Bottom you get String.
      If the input reference is a formal type parameter declared on a method, adaption is only possible if this adaptor was created using TypeAdaptor(CtMethod). Otherwise, there is no reference method to adapt to and the input will be returned unchanged.
      If that constructor was used, this method will return the corresponding type parameter declared on the context method of this adaptor.
      Parameters:
      superRef - the super type to adapt
      Returns:
      the adapted type
    • adaptType

      public CtTypeReference<?> adaptType(CtType<?> superType)
      Adapts a type from a supertype to the context of this adaptor.
      Parameters:
      superType - the super type to adapt
      Returns:
      the adapted type
      See Also:
      adaptType(CtTypeReference)