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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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<String>.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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
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?
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
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<String>.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
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!
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
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!
Hi!
As a workaround, you should retrieve the latest version from the SVN
repository. I just commited a bugfix for your issue ;)
/Tobias