Skip to content
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

Issue with "Call Hierarchy" and Groovy properties #936

Open
mauromol opened this issue Aug 9, 2019 · 6 comments
Open

Issue with "Call Hierarchy" and Groovy properties #936

mauromol opened this issue Aug 9, 2019 · 6 comments

Comments

@mauromol
Copy link

mauromol commented Aug 9, 2019

Maybe this is related to the improvements you made for 3.4.0 and you cite in the release notes (paragraph "Call Hierarchy and Find Occurrences"), but I feel like there's a problem with Call Hierarchy invoked on class properties on recent builds (maybe it has always worked like this? I can't check).

Consider the same example code as in #935: if I invoke Ctrl+Alt+H on MyBean.foo I don't get any results, while I would expect to find the access at Test53.doSomething(), which is indeed an implicit setter call.

I don't know the internals, but it seems like invoking Call Hierarchy on a field causes that view to be set in "property access" mode rather than in "method call" mode. And, from this point of view, what I see for the example in #935 is correct (i.e.: there's no direct field access). However with Groovy, since we indeed have implicit getter and setter methods generated for that property, an actual "method call" reference exists for MyBean.foo and it's the one I would expect to find in the Call Hierarchy.

Indeed, I would have assumed "Call Hierarchy" just shows "method Calls": in fact when I read the 3.4.0 release notes I did not agree with the change you mention about implicit-this references, because for that case Groovy uses direct field accesses, not method calls. However I just realised that "Call Hierarchy" actually shows field accesses when invoked on class fields, so you are right and I was wrong... Nevertheless, I feel there's something unexpected here.

What do you think? Is there a way to make Call Hierarchy work in a "mixed" mode, showing both field accesses and implicit method calls for class properties?

@eric-milles
Copy link
Member

Call Hierarchy does not perform search like Find Occurrences or Refactoring does. The search participant extensions are not invoked. It is these extensions that provide support for Groovy properties and property-like use of getters/setters.

I'd need to do some more investigation. to see if there is anything that can be done to improve Call Hierarchy. It should work fine when invoked on fields and methods.

@mauromol
Copy link
Author

mauromol commented Apr 16, 2020

Another way to see the same inconsistency I described here.

Suppose you have a Groovy class GBean with a property foo.
Suppose now you have a Java class that uses a GBean instance and calls gbean.setFoo(...) and you invoke Call Hierarchy on setFoo(...): you would expect to see the "Members calling..." results for the generated setFoo(...) method, instead you'll get the "Members accessing..." results for the GBean.foo field in the Call Hierarchy View, which of course does not include the gbean.setFoo(...) call in the Java class from which you issued the command.

In summary: the Call Hierarchy is one of the tools I use more in Eclipse every day (I think it's one of the most useful in absolute) and, although the great improvement you made for it to work with Groovy code, it's still unreliable when dealing with Groovy code because of this inconsistency, which is really unfortunate.
I still believe that for Groovy properties, the Call Hierarchy should in some way combine methods calls and field accesses together, perhaps in different subtrees in a fashion similar to what you get when you invoke it on a method defined in an anonymous inner class:

immagine

Imagine here you invoked Ctrl+Alt+H on a property or on a generated setter/getter call and you had three nodes:

  • [setter calls] => for property modifications made with either explicit or implicit setter method calls
  • [getter calls] => for property reads made with either explicit or implicit getter method calls
  • [field accesses] => for direct property read/write accesses

each of them with their related invocation subtree...

Only in this way you will have the information that you're probably querying the IDE for when you invoke Ctrl+Alt+H.

@mauromol
Copy link
Author

Please note that, as of today, call hierarchy is still almost useless with Groovy tooling and it's a huge penalty compared to Java tooling.

@eric-milles
Copy link
Member

What would be the difference between Call Hierarchy and Find References for a field or property versus a method. That is, what is the purpose of Call Hierarchy for a Java field?

I'm very used to Find References for both fields and methods in Java. Groovy properties are somewhere in between, but I think the reference searching is decent for classes -- traits may still have some edge cases. I don't really understand Call Hierarchy, so I don't make use of it.

@mauromol
Copy link
Author

mauromol commented Nov 17, 2021

Call Hierarchy is one of the most useful features in Eclipse.

I rarely use it for fields (mainly because fields are usually encapsulated), I daily use it for methods. It's the fastest way to get an idea on where and how a method is used. The main difference wrt Find References is that the latter is just a flat view of the direct calls to a method (i.e., the first level of the Call Hierarchy), while Call Hierarchy allows you to navigate call stacks. Depending on how a method is used, trying to figure it out with Find References can be a headache, while it's just all in one view with Call Hierarchy.

Groovy properties are a special beast because they involve either direct access (when inside a class) or accessor (getter/setter) method calls (when outside the class).

If I have:

public class MyClass {
   private String foo;

   public String getFoo() { return foo; }
   public void setFoo(String foo) { this.foo = foo; }
}

in Java, I can easily invoke Call Hierarchy on either getFoo() or setFoo(String), while I can't really do the same right now for an equivalent Groovy class:

class MyClass {
  String foo
}

because Call Hierarchy on Groovy properties right now adopt the Java approach for field references, and hence list just direct field accesses inside MyClass, completely ignoring external accesses through "synthetic" getters and setters.

If I want to know how (not just where) MyClass.foo is accessed in my workspace, I currently need to invoke Find References multiple times, jump here and there, return to Find References view history when I have exhausted a call path, proceed with the second path and so on.

@eric-milles
Copy link
Member

The multiple trees (aka [callers] and [constructors]) comes from deep within CallHierarchyCore.

There is the possibility of handling multiple elements (field, getter, setter) from an API level. The default behavior is to put up a selection dialog when code select returns multiple elements. Maybe there is a way around this, but it is not straightforward.

I also looked at the searching and why it is different from java element searching. JavaSearchQuery is used for Find References and makes use of registered query participants. Call Hierarchy does a plain search so there is no participant interaction. But there is a chance to modify the pattern as it flows through patchable code at one point. I may be able to try this as an experiment and see what kind of results are possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants