Menu

TypeArgumentDeclaration vs. TypeArgument?

Developers
widheg
2009-10-27
2012-10-08
  • widheg

    widheg - 2009-10-27

    In terms of Java source code, what is the distinction between a
    TypeArgumentDeclaration and a TypeArgument?

    I have an instance of recoder.abstraction.ParameterizedType (named 'pt') and I
    want to infer the type of each type reference that appear in each type
    argument of 'pt'. So I call pt.getTypeArgs() and get a list of type arguments.
    I loop through that list and get each type argument. How do I then move on
    from there?

    Note, for a TypeArgumentDeclaration I know how to do this.

    Note, the distinction between a TypeParameterDeclaration and a
    TypeParameter is clear to me.

    Thanks for any illuminating hints!

     
  • Tobias Gutzmann

    Tobias Gutzmann - 2009-10-28

    Hej,

    a TypeArgument is an abstraction (in recoder.abstraction) .
    There are currently four subtypes of TypeArgument:
    - in .class files: recoder.bytecode.TypeArgumentInfo
    - in source code: recoder.java.declaration.TypeArgumentDeclaration
    - for internal use 1: recoder.service.DefaultProgramModelInfo.ResolvedTypeArgument is, e.g., used when the return type of a generic method has been resolved
    - for internal use 2: recoder.service.DefaultProgramModelInfo.WrappedTypeArgument is used to convert a type to a type argument. Actually, I should look into this, it simply looks like a special case of ResolvedTypeArgument

    TypeArgumentInfo is, e.g., created when you load the class java.lang.String:
    It has, as one supertype, Comparable<String>. (Note that, while
    many people claim that all information concerning generics is removed from
    bytecode, that simply is not the case).

    Anyway, the two "internal" cases are not visible, so you need to
    address them using the TypeArgument interface.

    However, I am not 100% sure that I understand what you want to do... Can you
    post your source code?

     
  • widheg

    widheg - 2009-10-28

    Hej, and great thanks for replying by the way!
    What I'm trying to do is to capture and store types that appear in Java source
    code -- (this is one part of capturing various data for later processing).

    So if I understand you correctly instances of the two classes
    TypeParameterDeclaration and TypeArgumentDeclaration should be possible to
    state in terms of Java code (since they are a part of the
    recoder.java.declaration package)? I have no notion of what a
    TypeArgumentDeclaration really is. In my notion, one declares a type
    parameter (tp), not a type argument. Once a tp has been declared there may be
    occurences of that tp. Is the intention that each occurence of a tp
    (including its declaration) is represented by the class
    TypeParameterDeclaration?
    For a type argument (ta) on the other hand, since I have no notion of a
    declaration of it, I guess that one instance of the class
    TypeArgumentDeclaration represents one occurence of a ta -- is this correct?
    If you have a notion of the distinction between a TypeParameterDeclaration and
    a TypeArgumentDeclaration in terms of Java source code, please state some
    brief example code.

    My visitMethodDeclaration(MethodDeclaration x) retrieves any type parameter
    declarations made within that method (by calling x.getTypeDeclarationCount()
    and x.getTypeDeclarationAt(i) ), and calls visitTypeParameter() for each such
    declaration (note 1).
    My visitTypeParameter(TypeParameterDeclaration x) calls
    x.getTypeReferenceCount(); TypeReference tr = x.getTypeReferenceAt(i); Type type = sc.getSourceInfo().getType(tr)
    in order to retrieve the types being referred within the tp-decl. In addition
    my visitTypeParameter() also calls tr.getTypeArguments() to retrieve any ta
    occurences, and for each occurence calls
    visitTypeArgument(TypeArgumentDeclaration x) to capture the type of the ta
    (note 2). (It then detects any ta:s of the current ta and calls itself
    recursively.)

    Note1) This does not capture type parameters declared within the method's
    formal parameter list though, only the e.g. 'T extends E' that appears left of
    the method's return type.

    Note 2) However, calling x.getTypeReferenceCount() from here will include the
    input ta itself in the count, whereas calling it from within
    visitTypeParameter() the input tp is not included in the count.

    Thanks for any help or hints!

    PS Any mistakes or omissions are due to my somewhat rusty practice in Java
    generics ;-) DS

     
  • Tobias Gutzmann

    Tobias Gutzmann - 2009-11-02

    Hej!

    TypeArgumentDeclaration may be a not so good naming, but what's done is
    done ;-) Anyway, it is a type argument that occurs in source code. Example: In
    List<? extends Number>
    the "? extends Number" is a TypeArgumentDeclaration.

    A TypeParameterDeclaration is always part of another declaration, namely
    either of a MethodDeclaration or a TypeDeclaration. Thus, a
    TypeArgumentDeclaration is kind of "applied" to
    TypeParameterDeclarations, just like arguments to a method are
    "applied" to its formal parameters.
    More examples:
    interface ListOfLists<T extends List> extends
    java.util.List<T> { ... } - "T extends List" is a
    TypeParameterDeclaration, whereas "T" is a TypeArgumentDeclaration.
    public <T> T foo(T t) { return t; } - the first "T" is a
    TypeParameterDeclaration of the method. It determines its (static!) return
    type based on the static type of the argument passed to the parameter
    "t". Or, the method could even be invoked explicitly:
    this&lt;String&gt;.foo(null); will have a static type of
    "String". If the type argument "String" is not passed,
    then something called "type inference" is performed.

    Regarding your note 1:
    I cannot see how a type parameter could be declared in a method's formal
    parameter list (they can only be referenced)

    I think some of the source code you provided got lost in the formatting.
    Please post it again if you have further question.

    Best regards,
    Tobias

     
  • widheg

    widheg - 2009-11-04

    First of all thank you Tobias for your answer, which was very useful! Related
    to this I need to ask/get confirmation on four small samples:

    1) Let identifier 'x' be of type TypeParameterDeclaration. One can call
    x.getTypeParameters();
    to get a ASTList of TypeParameterDeclaration.
    In what cases does that call return something else than null?

    2) Consider the following method declaration:
    public <T extends Number> void method03(int a, List(List(T)) b) {;}
    In the method's formal parameter list, is the entire "List(T)"
    considered as one TypeArgumentDeclaration of the outer List?
    In turn, is "T" then considered as one TypeArgumentDeclaration of
    the TypeArgumentDeclaration "List(T)"? (To avoid formatting issues,
    I use paranthesis instead of angle brackets here.)

    3) Let identifier 'x' be of type TypeParameterDeclaration. Can a call to
    x.getTypeReferenceCount()
    return anything else than 1? If so, please provide a sample code.

    4) Let 'x' be of type MethodDeclaration.
    Type type = x.getReturnType();
    if (type != null)
    type.getFullName();

    The call to type.getFullName() above returns a string e.g.
    "testdata.TestClass23.16993205.T" ("testdata" here is
    target's package name.)
    What does 16993205 denote?

    The target code is:
    public <T> T method10(int a, int b) {...}

    I would guess that a number like "16993205" somehow indicates that
    type parameter T is declared on method level as opposed to on class level. But
    how to transform that number into something meaningful to a user e.g. a method
    name or signature?

    Thanks for reply!

     
  • Tobias Gutzmann

    Tobias Gutzmann - 2009-11-05

    Hi!

    glad I can help :)

    1) is always "null", as a type parameter cannot declare further type
    parameters. Only MethodDeclarations and "regular" TypeDeclarations declare new
    type parameters.

    2) yes. Your description is correct. List<T> is a TypeArgument, so is
    <T>.

    3) yes. getTypeReferenceCount() returns the number of bounds declared
    explicitly in source code
    Examples:

    class Q<T> <- "0"
    class Q<T extends Number> <- "1"
    class Q<T extends Number & Serializable> <- "2"
    etc...

    Note that getBoundCount() always returns a minimum of "1", as java.lang.Object
    is an implicit bound (this is done so that both TypeParameterInfo and
    TypeParameterDeclaration behave the same).

    4) The "address in memory" of the method for this run of your program. It will
    usually change with every program run. This is just like anonymous and local
    classes are treated. There is no "global" name to reference them. I'm afraid
    that Recoder does not provide a mechanism to make the name something
    meaningful. You can write it yourself, by evaluating type.getASTParent() ->
    will return a MethodDeclaration in this case.

    Best regards,

    Tobias

     
  • widheg

    widheg - 2009-11-06

    Much thanks again Tobias!
    Concerning question 3 above, I just noticed that if one uses an index of 1 as
    argument to getTypeReferenceAt(index), then the exception
    java.lang.ArrayIndexOutOfBoundsException is thrown.
    In my example, getTypeReferenceCount() returns a value of 2, which is correct
    for my target code. Then I call getTypeReferenceAt(index) in a simple loop,
    first turn (index=0) in loop goes ok but in the second turn (index=1), the
    exception is thrown from TypeParameterDeclaration.java.

    Thanks again for any hints or workarounds!

     
  • Tobias Gutzmann

    Tobias Gutzmann - 2009-11-06

    Hi!

    As a workaround, you should retrieve the latest version from the SVN
    repository. I just commited a bugfix for your issue ;)

    /Tobias

     

Log in to post a comment.