-
-
Notifications
You must be signed in to change notification settings - Fork 346
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
[question] method call hierarchy #2014
Comments
This can be done. You can parse through all the CtInvocations. For a particular CtInvocation, let's call it element: you can get the function name by element.getExecutable(), which returns a CtExecutableReference. You can get list of arguments by element.getArguments(). Just check whether function name is equal to "externalServiceCall". I didn't quite get your third point. |
Third point is meant like if |
Now I have something like this:
and getting following issue:
Am I doing something wrong? It is multimodule maven project so I don't know if I should us |
you should activate noclasspath mode
|launcher.|setNoClasspath(true);
|
it's the second line in unit test and it doesn't work |
sorry, I missed the line;
Then it's maybe a bug.
What if you use the MavenLauncher?
|
I'm pretty sure it is the same thing as this: #1975 |
Hi, @tdurieux yes that looks like the same problem |
could this be helpful? |
thanks for the link it will be useful. Can you try again with this dependency in your project <dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.annotation</artifactId>
<version>2.0.0</version>
</dependency> |
yes I've tried that in meantime but unfortunatelly it doesn't work. I also found this issue where they are configuring jdt. I don't know if that could help. |
I pushed a solution in #1975! |
That solved this problem but now I get |
did you provide the path the source folder or to root of your project? |
To be clear. I have multimodule maven project (huge one).
line 25 is last line in following code:
|
is Xyz a generated file? I should fix this in MavenLauncher. I create a pr #2020 for the NPE |
small steps, but we are moving somwhere :D Just to mention Xyz was regular class, but I'm using lombok in my project. Could that be issue for some operations?
|
I created a new pr #2021 for this NPE, you will help us to remove all npe from spoon.
lombok probably generates the class in target/generated-class and I include this folder with MavenLauncher thus the class is duplicated. I don't know what is the good strategy |
hmm now weird one...I have querydsl-core on classpath
|
Can you check that the jar is present in launcher.getModelBuilder().getSourceClasspath()? |
actually it's not present there. It is transitive dependency |
does the parent dependency is present in the classpath? |
No the parent dependency is not present tehre. To be clear I don't see any of my or parent jars. |
and I suppose that the project you are working on is not publicly available |
you are totally right :( but let me try something. |
Do you use range version in this project? |
what is range version? I tried the setup on this project and it also fails on simillar issue. |
in maven you can say to use one version between 1.12 and 1.15 or any version above something |
Nullpointer here
I'm on your branch...don't know if need something else to merge |
you should merge maven launcher pr. |
On project (core) which I was referencing now it seems to be working. I will prepare some kind of application and ask you if you can help me to manage how to solve my original question. |
The request that you launched is browse several time the AST which is really not efficient Something like this will be more efficient. List<CtExecutableReference> allMethods = launcher.getModel()
.getElements(new TypeFilter<>(CtMethod.class))
.stream().map(m -> m.getReference()).collect(Collectors.toList());
launcher.getModel().getRootPackage().accept(new CtScanner() {
@Override
public <T> void visitCtInvocation(CtInvocation<T> invocation) {
if (invocation.getExecutable().isConstructor()) {
return;
}
for (CtExecutableReference<?> executable : allMethods) {
if (invocation.getExecutable().getSimpleName().equals(executable.getSimpleName())
&& invocation.getExecutable().isOverriding(executable)) {
System.out.println(executable + "=>" + invocation);
}
}
}
}); |
I rebase my PR about maven-launcher, can you try again this branch? Thanks |
if this is the branch you are referencing, then there is nullpointer.
|
no this one: #2024 |
That seems to be working |
Btw I've updated the sample project with some sources which are simplified something that I need to analyze in my application. this method is that one which calls all external services. I need all it's parent invocations where I can find first parameter (so this and this) and then from there I need to search for all calling methods and find methods which are annotated with Can you help me with that please? I can't get my head over that. |
Finally! Thank you for all the time you took to reproduce and report the issues! |
If I correctly understand you have
You want to find all the methods that call |
Yes that's correct, but I want one extra thing and that is. method directly invoking
Don't bother with retrieval of annotation values (like |
this should work CtClass<?> aClass = factory.Class().get("com.github.bilakpoc.spoon.integration.AbstractIntegrationCaller");
CtMethod<?> ctMethod = aClass.getMethodsByName("callExternalService").get(0);
List<CtMethod> callers = ctModel.getElements(new TypeFilter<CtInvocation>(CtInvocation.class) {
@Override
public boolean matches(CtInvocation element) {
CtExecutableReference executable = element.getExecutable();
if (executable.getSimpleName().equals(ctMethod.getSimpleName())
&& executable.isOverriding(ctMethod.getReference())) {
return true;
}
return false;
}
}).stream().map(i -> {
CtMethod parent = i.getParent(CtMethod.class);
parent.putMetadata("ExternalService", i.getArguments().get(0).toString());
return parent;
}).collect(Collectors.toList());
CtTypeReference<? extends Annotation> requestAnnotation = factory.Type().createReference("org.springframework.web.bind.annotation.RequestMapping");
ctModel.getRootPackage().accept(new CtScanner() {
@Override
public <T> void visitCtInvocation(CtInvocation<T> invocation) {
CtExecutableReference<T> executable = invocation.getExecutable();
for (int i = 0; i < callers.size(); i++) {
CtMethod method = callers.get(i);
if (method.getSignature().equals(executable.getSignature())) {
CtMethod parent = invocation.getParent(CtMethod.class);
CtAnnotation<? extends Annotation> annotation = parent.getAnnotation(requestAnnotation);
if (annotation != null) {
System.out.println(method.getMetadata("ExternalService") + " -> " + annotation.getValue("value").toString());
}
}
}
super.visitCtInvocation(invocation);
}
}); |
Hi @tdurieux that works.
I'm still working only on this sample project to understand what should I do, then I will try on that big project and will let you know if there is everything ok. |
Spoon is a static analysis tool, it has not been designed for interaction with the running state:/ But there the method Class A snapshot of spoon is pushed everyday on maven central, I need to finish my PR maven-launcher |
We have |
@monperrus in which version is it? I don't see it here |
It is on CtExecutableReference.getActualMethod() |
I've updated the project and I think for test project I'm satisfied. I will work on private project maybe next week. Just that last question. When will be this changes available in maven central? Do you have any release plan? |
the releases are every 3/4 months depending of the content but the snapshot is deployed every night thus once the pr is merged the next day you have the features in maven central. |
In fact there should be a release coming before the end of the month. So if the changes are already in master, stay tuned the release is coming :) |
Hi I'm playing with code. I don't understand one thing. When I run test project everything seems to be ok. Even if I add another controller with deeper strucutre eg |
No you will only get the method that directly call |
And what is the simplest way to create that call graph. I was thinking about moving this function to separate method (processing) and call it recursivelly -> check if extracted method has annotaiton if no get callers of currently processing method and call procesing method again. But I don't know if this is correct aproach. |
btw I've updated the project. And you can see that I've added another controller which has more than one nested "service" and the result is ok. So why in this case it's working? |
It should work, but the performance costs of this function is high I don't know if it is ok for you
Because the signature of the method did not change. |
I see that this is that problem which I didn't recognized before. So could you please suggest some mechanizm how to create the call graph? |
@tdurieux can you please explain to me what is the way to search for parent invocations if there is change in method signature? e.g. if I have calls to
I want to traverse from thanks |
with |
Hello,
I'm new to spoon and I'm wondering if following is possible to do with spoon.
I have method
externalServiceCall(...)
which is called from many places in my application. Can I have call hierarchy to this method?What I want to achieve is that I will generate mappings of my @RestController to
externalServiceCall(...)
.this is what I'm thinking about:
externalServiceCall(...)
Service
interface (with this I can extract the name of service)externalServiceCall(...)
and go upper until I find some annotation on method. In this case I'm searching for spring's @RequestMappingSo in final I can have something like:
this is example of how the externalService call looks like
externalServiceCall(ProductServiceEnum.GET_DETAIL, request)
...
The text was updated successfully, but these errors were encountered: