-
-
Notifications
You must be signed in to change notification settings - Fork 357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
About adapting type parameter of generic method, using actual invocation in AST. #4838
Comments
Hey, the tl;dr is that you are currently out of luck, there is no inbuilt solution. What Spoon offers currentlyI recently rewrote type adaption and created the new MethodTypingContext()
.setClassTypingContext(new ClassTypingContext(classA))
.setInvocation(invocation)
.adaptType(e) // => String? So, just use the old API, set the invocation and done. Easy, right? Not quite. Spoon only considers explicitly annotated type arguments in invocations. The actual type arguments of the invocation How that could be improvedTo be usable, Spoon would need to ask JDT for the types it inferred for invocations and then use them as actual type arguments. This might be possible if somebody implements it, but is then limited to code parsed by JDT. If you create your own code using the spoon API, you would need to supply them yourself. If you transform the model and you aren't really diligent, that information will be incorrect or missing. (Yes, this section exists just to yakbait somebody into implementing this. The alternative is implementing the java type inference rules in spoon and adapting them for each java version, which could be an interesting project but is a really, really bad idea:tm:) How you could maybe fake it yourselfYou might, however, be able to just do it yourself. Depending on your usecase, using the type of the arguments of the CtInvocation could be enough. In this case you would ask the String literal for its type, which is |
I really appreciate for the detailed answer. The code snippet you attached seems useful to me. The good news is, I'm using Spoon version where
Actually, in the Java programs I'm working with, explicit annotation rarely occur. I think I have to do it by myself. Thank you for your detailed hint. |
@jiseongg With #4844 merged, this should now work: @ModelTest("/tmp/test")
void better(Factory factory) {
CtClass<?> classA = factory.Class().get("A");
CtClass<?> classTestA = factory.Class().get("TestA");
CtInvocation<?> invocation = classTestA.getMethodsByName("test").get(0)
.getBody()
.getStatement(0);
CtTypeParameter e = classA.getMethodsByName("genericMethod").get(0)
.getFormalCtTypeParameters().get(0);
System.out.println(
new MethodTypingContext()
.setClassTypingContext(new ClassTypingContext(classA))
.setInvocation(invocation)
.adaptType(e)
);
} I am not a fan of the old class typing context though, but I am also not quite sure what exactly you need here. The main question I have is whether you need to resolve generics defined foe the enclosing class, e.g. class Top<T> {
void foo(T t);
}
class Bottom<R> extends Top<R> {} Do you want to resolve the type of the parameter If you do not require this, what you desire should be exactly the result of calling |
@I-Al-Istannen, thank you for your effort to make such PR. It is what I need. For the additional example you gave, I'm not sure I need such feature right now. I think I have to share how I'm using Spoon. What I'm doing with Spoon is analyzing existing Java projects statically to gather some useful information and utilize it to enhance automatic test case generation engine. Until now, it has been mostly about generics. For example, automatic test case generator goes through difficulties to test Considering my use case, with the example you've given, the most desirable feature I want is the way to resolve class new TestBottom {
public class test() {
Bottom<Integer> bot = new Bottom<>();
bot.foo(3);
}
} But, I suppose this is possible already, isn't it? I've used spoon like below.
I'm sorry if there is some misusage causing misunderstanding, since I'm not in my workplace now. To sum up,
until now, I haven't experienced the situation I had to resolve |
Well, I would change the last line to Apart from that, your code correctly handles one special case. If that is all you need, you are fine :) If you have a method public class Test<T> {
public void foo(List<T> list) {}
} you will need to adapt the parameter's type instead though: CtExecutable<?> calledExecutable = invocation.getExecutable().getExecutableDeclaration();
CtTypeReference<?> parameterType = calledExecutable.getParameters().get(0).getType();
System.out.println(new TypeAdaptor(receiverObjectType).adaptType(parameterType)); But this still works just fine, no problem there. Where things start to break down are cases like: class Test {
public static <T> void foo(T t) {}
}
// and somewhere an invocation
Test.foo(20); With my PR, the type the eclipse compiler inferred for such a call will be stored in To solve this, you can use CtExecutable<?> calledExecutable = invocation.getExecutable().getExecutableDeclaration();
CtTypeReference<?> parameterType = calledExecutable.getParameters().get(1).getType();
System.out.println(
new MethodTypingContext()
.setClassTypingContext(new ClassTypingContext(receiverObjectType))
.setInvocation(invocation)
.adaptType(parameterType)
); which returns |
Oh, I've just understood what you're wondering. I think it'll be great if such API exists. (regardless whether this kind of operation has been used a lot historically.) Making new One thing I wonder about the code new MethodTypingContext()
.setClassTypingContext(new ClassTypingContext(receiverObjectType))
.setInvocation(invocation)
.adaptType(parameterType) is whether |
The class typing context (or, equivalently, the constructor argument of class Top<T> {
public void foo(T t) {}
}
class Sub extends Top<String> {} And you are resolving For now you can use the method typing context, I will see if I can come up with something. It's not really type adaption, it is adapting the method first and then replacing its formal type parameters with the actual types recursively. |
Hi,
I'm looking for the way to extract type adapting rule from AST. For generic class, there is ClassTypingContext. Is there any equivalent concept in
CtExecutable
? I've triedMethodTypingContext
but I'm not sure it can be used for my purpose.Example:
I want to extract the information from the AST of
TestA
above, which tells me that the type parameterE
is actually injava.lang.String
.Below is what I've tried roughly and it cause errors. Also, note that I'm not sure about the actual usage of
MethodTypingContext
The text was updated successfully, but these errors were encountered: