Bug 171019 - [javadoc][select] F3 on {@inheritDoc} tag should navigate to target javadoc
Summary: [javadoc][select] F3 on {@inheritDoc} tag should navigate to target javadoc
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.3   Edit
Hardware: PC Windows XP
: P3 enhancement with 2 votes (vote)
Target Milestone: 3.7 M6   Edit
Assignee: Ayushman Jain CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 118648 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-01-19 04:51 EST by Frederic Fusier CLA
Modified: 2011-03-07 13:03 EST (History)
6 users (show)

See Also:
Olivier_Thomann: review+


Attachments
proposed fix v1.0 (8.97 KB, patch)
2011-02-17 01:30 EST, Ayushman Jain CLA
no flags Details | Diff
proposed fix v2.0 + tests (24.71 KB, patch)
2011-02-22 07:41 EST, Ayushman Jain CLA
no flags Details | Diff
proposed fix v2.1 + tests (29.60 KB, patch)
2011-02-23 06:09 EST, Ayushman Jain CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Frederic Fusier CLA 2007-01-19 04:51:39 EST
It would be nice if it was possible to navigate through the inherited method through the {@inheritDoc} tag when present in a javadoc comment.

For example in following test case
public class Y extends X {
X.java:
    public class X {
	/**
	 * Main description of the method foo...
	 *
	 * @param obj The given object
	 * @return an empty string
	 * @see Object the root class
	 * @see String the string class
	 */
	public String foo(Object obj) {
		return "";
	}
    }

Y.java:
    public class Y extends X {
	/**
	 * Specific description of the overriding method...
	 *<br>
	 * {@inheritDoc}
	 * @return <code>null</code>
	 */
	public String foo(Object obj) {
		return null;
	}
    }

I expect to jump to X.foo javadoc comment when hitting F3 on the {@inheritDoc] inline tag...
Comment 1 Frederic Fusier CLA 2007-01-19 04:53:10 EST
Not sure if there was any changes need in JDT/UI for this or only return the correct selected element would be enough?
Comment 2 Markus Keller CLA 2008-07-02 14:17:59 EDT
Should also check hyperlinking (Ctrl+click) in the Java editor when codeSelect works.
Comment 3 Dani Megert CLA 2008-07-03 03:17:10 EDT
*** Bug 118648 has been marked as a duplicate of this bug. ***
Comment 4 Dani Megert CLA 2010-06-21 07:05:59 EDT
I'd like to see this fixed for 3.7.
Comment 5 Ayushman Jain CLA 2010-06-21 07:48:18 EDT
I'll follow up.
Comment 6 Ayushman Jain CLA 2010-09-10 15:45:06 EDT
(In reply to comment #5)
> I'll follow up.

This is a bit more complicated than I thought. The SelectionJavadocParser currently relies on ASTNode for a type,method, field, etc when it needs to be parse the reference after a tag such as @see, or @param. Code select currently does not have any infrastructure to work with inline tags without any accompanying ASTNode. Even the method for which the javadoc contains the @inheritDoc and the type defining the method are not available to the SelectionJavadocParser when parseTag(int) is called.
Comment 7 Ayushman Jain CLA 2011-02-17 01:30:55 EST
Created attachment 189151 [details]
proposed fix v1.0

This patch makes the SelectionJavadocParser record that selection has taken place on an @inheritDoc inline tag, so that the SelectionEngine can process the node that we need to navigate to. Using this, F3 works fine.

The SelectionRequestor can only accept an IJavaElement. Since javadoc is not really an IJavaElement, our best best is to add the corresponding method declaration to the SelectionRequestor's list. So pressing F3 on inheritDoc navigates to the overriden method. I feel this is ok because the inherited doc is anyways just going to be right on top of the overriden method declaration.

The problem, though, is when one presses CTRL + Click on the @inheritDoc tag, the UI processes it in the same fashion as it would if one does a CTRL+click on a method. Markus, Can anything be done to alter this behaviour for @inheritDoc tags?
Comment 8 Dani Megert CLA 2011-02-17 05:17:15 EST
(In reply to comment #7)
> Markus, Can anything be done to alter this behaviour for @inheritDoc
> tags?
We can take a look into Ctrl+Click once it's working for F3 (the detector needs to be adjusted).
Comment 9 Markus Keller CLA 2011-02-17 08:57:10 EST
(In reply to comment #7)
> So pressing F3 on inheritDoc
> navigates to the overriden method. I feel this is ok because the inherited doc
> is anyways just going to be right on top of the overriden method declaration.

Yeah, I guess that's the best we can do.

I didn't try the patch, but from looking at the code, it seems you just find any overridden method in the hierarchy. Unfortunately, the real {@inheritDoc} algorithm is more complex, since it can also inherit the doc from further up the hierarchy. This is comparable to "super.method()", which can also jump multiple super classes until it finds the right one. Note that not all {@inheritDoc} tags in the same Javadoc refer to the same super spec.

See the implementation we use in the Javadoc hovers in
org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2.InheritDocVisitor and the links to the spec there.
Comment 10 Ayushman Jain CLA 2011-02-17 11:18:48 EST
(In reply to comment #9)
> See the implementation we use in the Javadoc hovers in
> org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2.InheritDocVisitor
> and the links to the spec there.

Ok so it seems like I just implemented the InheritDocVisitor.visit() method (looking at its implementation in org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2.findAttachedDocInHierarchy(IMethod), it used MethodOverrideTester to find the overriden method, which seems to do what my findOverriddenMethodInHierarchy(..) does.).I still need to deal with the remaining pieces. And, as i understand, that would be for cases where the javadoc is not on the immediate super method , but still some levels above, right?
Comment 11 Markus Keller CLA 2011-02-17 12:42:21 EST
JavadocContentAccess2#findAttachedDocInHierarchy(..) is just our fallback when we don't have attached source and still want to find at least some Javadoc for binary elements. That's not what we should do here.

InheritDocVisitor has indeed been written to help with cases where inherited doc snippets (from main doc, @param, @return, or @throws/@exception) need to be found anywhere in the super hierarchy.
Comment 12 Ayushman Jain CLA 2011-02-18 07:44:20 EST
The problem is how to figure out whether a particular method, which has been determined to be overriden following the InheritDocVisitor algorithm, actually contains a javadoc or not. Javadoc can be obtained via java elements, but in this case i only have the compiler bindings, from which i can't obtain a java element.

I was also thinking, wouldn't it be easier to implement in the UI itself, if jdt/core can add the current method into the requestor and set a flag signalling that the selection took place on the inheritDoc tag?
Comment 13 Markus Keller CLA 2011-02-18 09:58:10 EST
> I was also thinking, wouldn't it be easier to implement in the UI itself, if
> jdt/core can add the current method into the requestor and set a flag
> signalling that the selection took place on the inheritDoc tag?

There's no requestor at the API level. We only have ICodeAssist#codeSelect(..) that returns an IJavaElement[].

I agree that the resolution of inheritDoc tags is not trivial, but that would rather speak for offering an API for this in jdt.core than implementing everything in the UI.
Comment 14 Markus Keller CLA 2011-02-18 10:02:37 EST
And in the UI, we have exactly the same problem that we don't have ASTs of the super types at hand, and that we have to create these on-the-fly if necessary to find the inherited doc.
Comment 15 Ayushman Jain CLA 2011-02-18 10:35:18 EST
(In reply to comment #13)
> I agree that the resolution of inheritDoc tags is not trivial, but that would
> rather speak for offering an API for this in jdt.core than implementing
> everything in the UI.

Actually, the whole issue is just extracting the javadoc out of a method to make sure the method code select is returning is the one where javadoc is being inherited from. And i'm having a tough time  trying to figure out how to achieve that in the SelectionEngine. My first reaction was that since the UI hovers already fetch the correct javadoc when I move the cursor over a method with inheritDoc tag, and also since JavadocContentAccess and JavadocContentAccess2 has all functionality in place to do so, it should be a trivial task for the UI. By API, do you mean we should move this down to jdt.core? 

Even the perProjectInfo doesn't seem to have the javadoc in this case, so I dont understand how to fetch it.
Comment 16 Markus Keller CLA 2011-02-22 07:05:01 EST
Core does not need to resolve the target of {@inheritDoc} for other reasons and UI already has most of the necessary infrastructure to resolve the tag in Javadoc hovers, so I think it's too much work adding this to jdt.core now.

Moving this to UI for a fix similar to bug 269112.
Comment 17 Ayushman Jain CLA 2011-02-22 07:07:33 EST
(In reply to comment #16)
> Core does not need to resolve the target of {@inheritDoc} for other reasons and
> UI already has most of the necessary infrastructure to resolve the tag in
> Javadoc hovers, so I think it's too much work adding this to jdt.core now.
> 
> Moving this to UI for a fix similar to bug 269112.

I have already made the necessary changes in core to fix this. I was just in the process of adding regression tests. Are you sure you want to move this to UI?
Comment 18 Ayushman Jain CLA 2011-02-22 07:41:34 EST
Created attachment 189479 [details]
proposed fix v2.0 + tests

This patch follows the correct algo for finding which method to navigate to, using the InheritDocVisitor of JavadocContentAccess.

The visit() method had to be adjusted to make sure that the current method being visited actually has a javadoc. 

The fix works for all cases - when all classes are in the source, when some classes in the hierarchy are binaries in external JARs with either source or javadoc attached, and even when all the classes are binaries in an external JAR with source attached.
Comment 19 Markus Keller CLA 2011-02-22 09:19:57 EST
(In reply to comment #18)
> Created attachment 189479 [details] [diff]
> proposed fix v2.0 + tests

OK, that looks smaller than I though it would become, and I also found no issue when testing it. To avoid the compiler warning, you may want to make the InheritDocVisitor package-visible.

OK to go if Olivier agrees.
Comment 20 Ayushman Jain CLA 2011-02-22 09:23:13 EST
(In reply to comment #19)
> (In reply to comment #18)
> > Created attachment 189479 [details] [diff] [details] [diff]
> > proposed fix v2.0 + tests
> 
> OK, that looks smaller than I though it would become, and I also found no issue
> when testing it. To avoid the compiler warning, you may want to make the
> InheritDocVisitor package-visible.

Ok, i'll clean up the patch.
Comment 21 Olivier Thomann CLA 2011-02-22 09:29:07 EST
+1
Comment 22 Ayushman Jain CLA 2011-02-22 10:03:48 EST
(In reply to comment #21)
> +1

Olivier, the patch contains a new method SelectionRequestor#findMethod(IType type, char[] selector, String[] paramTypeNames). The same was introduced in InternalCompletionProposal by Jay, to make sure we obtain the correct handle to the method and not just a dummy, so that the java model cache can be looked up to get the info about a method. Since it's already being used at 2 places now, and may again be used somewhere in the future, I suggest it to be made an API in IType, alongside getMethod(..) and findMethod(..) functions.
What do you think?
Comment 23 Markus Keller CLA 2011-02-22 12:48:32 EST
(In reply to comment #22)
The findMethod(..) implementations look wrong regarding their handling of constructors. A method can actually have a constructor name, but you can't distinguish these cases. You should add a boolean isConstructor parameter.

Then the method would be similar to our JavaModelUtil#findMethod(String, String[], boolean, IType).

The name 'paramTypeNames' is a bit odd, since this variable holds signatures, not names.

Before you can make this API, you need to rethink the general utility of the method. In an API, you can't just stop and return null if there are multiple matching methods. Note that IType#findMethods(IMethod) specs that it only compares simple names of the argument types (the implementation actually compares simple names of the erasure). This leaves it up to the client to do more thorough checks on the returned methods.

I don't see enough use cases where the proposed method would actually be correct, so I wouldn't add this as API.
Comment 24 Olivier Thomann CLA 2011-02-22 12:59:41 EST
I concur with Markus that we should only add an API if absolutely necessary. So if we can solve this case without adding new API, this would be better.
My +1 was for resolving it at the core level.
Comment 25 Ayushman Jain CLA 2011-02-22 13:05:48 EST
(In reply to comment #23)
> (In reply to comment #22)
> You should add a boolean isConstructor parameter.
Good point!
 
> Before you can make this API, you need to rethink the general utility of the
> method. In an API, you can't just stop and return null if there are multiple
> matching methods. Note that IType#findMethods(IMethod) specs that it only
> compares simple names of the argument types (the implementation actually
> compares simple names of the erasure). This leaves it up to the client to do
> more thorough checks on the returned methods.
> 
> I don't see enough use cases where the proposed method would actually be
> correct, so I wouldn't add this as API.

Yeah i agree. What i was actually looking forward was to avoid duplicating this method. So maybe we can add this to org.eclipse.jdt.internal.compiler.util.Util class.
Comment 26 Ayushman Jain CLA 2011-02-23 06:09:19 EST
Created attachment 189586 [details]
proposed fix v2.1 + tests

This is the cleaned up patch. Here's the explanation:
This patch fixes the problem in 2 parts:
1) Make sure SelectionParser parses the inheritDoc tag properly and sets a flag to denote that selection took place on inheritDoc tag. This needs to be done because the tag itself is not a valid AST node, and hence the SelectionNode can't really be created corresponding to this tag. So, the patch tries to build the SelectionNode corresponding to the method on which the inheritDoc tag is found and the boolean flag differentiates this case from the case when selection takes place on the method declaration itself. Changes in SelectionJavadocParser and JavadocParser take care of this part. org.eclipse.jdt.internal.codeassist.select.SelectionJavadoc.internalResolve(Scope) recognizes the flag and creates the SelectionNodeFound.

2) Make sure the SelectionEngine can find the desired method to navigate to, and adds it to the SelectionRequestor. This is done using the InheritDocVisitor class, taken from jdt.ui, which follows the spec on finding the correct method. Since in SelectionEngine, we only have the methodBinding, and an IMethod element is needed to find the javadoc (which we need to find to make sure the method we found actually has some javadoc that is being inherited). The implementation of InheritDocVisitor#visit() takes care of this.

All tests pass.
Comment 27 Ayushman Jain CLA 2011-02-23 06:11:43 EST
Olivier, can you please review? Thanks!
Comment 28 Olivier Thomann CLA 2011-02-24 15:22:35 EST
Looks good.
Comment 29 Ayushman Jain CLA 2011-02-28 03:56:44 EST
Released in HEAD for 3.7M6
Comment 30 Ayushman Jain CLA 2011-02-28 04:02:38 EST
Raised bug 338373 to take care of comment 8 above.
Comment 31 Olivier Thomann CLA 2011-03-07 13:03:47 EST
Verified for 3.7M6.