-
-
Notifications
You must be signed in to change notification settings - Fork 349
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
review ParameterReferenceFunction, ParameterScopeFunction #1136
Conversation
what's the role of the filter? |
Now I have committed the It is useful when somebody needs to check, whether method parameter is used. If not used then it is adept for remove - code cleaning refactoring. |
I'm using exactly this for an unused code detector that allows to find different elements that are not in use. |
See But technically it actually cannot be implemented without filter, because I need to call Solutions: list = element.map(new AllChildrenQuery()).list(); which is equivalent to this old code list = element.filterChildren(e->{return true;}).list(); |
But since I need a fast visitor I'm using the EarlyTerminationScanner. However, for very long methods it is not fast enough because there are too many elements to evaluate. |
@msteinbeck which project contains that code and class? Is it accessible somewhere? I do not want to reinvent wheel :-) |
Or do you mean the unused code detector? |
idea: I needed to found all the classes which inherits from class A. I needed that for many classes A. For such use cases it is better to scan model once and to store backreferenes using CtElement#putMetadata. Thanks to this you can then very fast solve some problems, because the result is cached in element metadata. idea 2: measure performance of "evaluation of element", may be there is some bottle neck. I do not believe that plain scanning of elements needs long time. I guess the evaluation is the problem. |
yes, both. I am interested in everything what helps might me :-) |
I'm using two sets for this. The first one stores the scanned elements I'm interested in and the second one stores all referenced elements. For the sake of performance, I'm using String HashSets. Each entry contains the qualified name of an element. At the end I'm using https://docs.oracle.com/javase/7/docs/api/java/util/AbstractSet.html#removeAll%28java.util.Collection%29 to extract all elements I'm interested in but are not referenced. That is very fast, though, I'm hashcoding and comparing Strings. |
I am sorry, I can't give you the full implementation now because we are working on a journal paper that wants to introduce enhanced techniques for automated code smell detection (and implementing a fast an precise unused code detector was very tough). Once it is published, I'll work on publishing the code :) |
It is worth mentioning that I'm using Spoon's references instead of resolving the actual types since type resolution takes quite some time. That is, if a type reference is visited, I'm using the qualified name returned by the reference rather than extracting the type declaration and using its qualified name. This lowered the detection time from 8 minutes to 4 seconds :D (for very large software systems). |
I have a problem with It's either a naming problem or a design problem. What do you think? |
I understand what you mean. |
OK, let's go for ParameterScopeFunction then. |
I came to simpler solution. We just have to make this running element.filterChildren(null) and optionally we might make it nicer with these 2 new mapping methods:
|
* CtQuery#filter(Filter)
We already have "map(Filter)"?
* CtQuery#allChildren()
This is an easy function. Should it include the input element?
It needs to be in setter because of ParameterReferenceQuery needs it actually
When and why?
|
no it is without input parameters. May be allChildren(boolean includingSelf), might be interesting.
see sources of this PR. They are short. |
I see, it's for extension. Since the reused behavior is one single line, I'd prefer to have no filter field, no setFilter method, and no inheritance, for sake of simplicity and understandability. |
OK, I agree. I will make another PR |
But if we will not allow setFilter, then we should think about Filter filter = new ...;
element.map(new ParameterScopeQuery).filter(filter)... otherwise the filtering is possible only using this not intuitive code Filter filter = new ...;
element.map(new ParameterScopeQuery).map(e->filter.matches(e))... And it will be even longer without java 8 lambdas. |
Filter filter = new ...;
element.map(new ParameterScopeQuery).map(e->filter.matches(e))... I like it, esp with lambdas, it's clear and explicit. Let's first aim at this simplest version. |
ok |
8cda5b3
to
617c203
Compare
Baby step 1 done:
Note: I have to add tests too. But let's agree on design first. |
And this PR needs PR #1140, otherwise it fails with |
b18d1ac
to
6ac5b05
Compare
I have added test of ParameterReferenceFunction. This test is originally designed to test VariableReferenceFunction, therefore test class contains parameters, fields, local variables and catch variables. May be it is hard to understand how this test works, but it efficiently checks that ParameterReferenceFunction
It depends on these PRs
|
e323f9b
to
59d74d0
Compare
67a4140
to
7cc7782
Compare
7cc7782
to
678d67c
Compare
it looks good to me. |
Ok for me, indeed the tests are the most difficult part of this PR! Thanks @pvojtechovsky :) |
First query of the set of PRs, which will be produced from #1114. It is the simplest one - good one to discuss basic topics.
Please decide:
Q1) Is the package
spoon.reflect.visitor.query
OK?Q2) I am not sure with the
filter
field, which does filtering of elements in scope of parameter visibility. It would be simpler to have query, which simply returns all elements in scope of parameter. And if somebody wants to filter them then s/he can applyCtQuery#map
in next query step. But it is true that actually I need filtering in all use cases ofParameterScopeQuery
, so may be it is correct.Any other feedback/idea?