Bug 209996 - [search] Add a way to access the most local enclosing annotation for reference search matches
Summary: [search] Add a way to access the most local enclosing annotation for referenc...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 enhancement (vote)
Target Milestone: 3.4 M6   Edit
Assignee: Frederic Fusier CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 79112
Blocks: 209625
  Show dependency tree
 
Reported: 2007-11-15 12:35 EST by Markus Keller CLA
Modified: 2008-05-15 12:14 EDT (History)
4 users (show)

See Also:


Attachments
Proposed patch (120.82 KB, patch)
2008-03-18 10:17 EDT, Frederic Fusier CLA
no flags Details | Diff
New proposed patch after initial Jerome's review (86.08 KB, patch)
2008-03-18 14:55 EDT, Frederic Fusier CLA
no flags Details | Diff
Last proposed patch (110.37 KB, patch)
2008-03-21 11:55 EDT, Frederic Fusier CLA
no flags Details | Diff
Proposed patch fixing comment 22 issues (114.63 KB, patch)
2008-03-22 09:40 EDT, Frederic Fusier CLA
no flags Details | Diff
Last proposed patch for M6 (114.86 KB, patch)
2008-03-23 12:13 EDT, Frederic Fusier CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2007-11-15 12:35:19 EST
Spawned from bug 155013 comment 18 to comment 24

>>> In case we later find that somebody needs more specific local elements, this
>>> could be added later, similar to how we've already done with
>>> TypeReferenceMatch#getLocalElement(), etc. .
> 
>> Can't getLocalElement() return the IAnnotation in this case and modify the
>> javadoc accordingly?

> Annotations can be used on local variable (bug 209778 is an example). In this
> case we could not used the local element to report both the local variable and
> the annotation.

That shouldn't be a problem if getLocalElement() always reports the "most local" of the local elements. Clients could just call getLocalElement() and then walk up the parent chain if they are also interested in parents.

E.g. in JDT/UI, we would *not* go up to the ILocalVariable when looking for similar elements to rename along with the type, since we're only interested in references that are in the declared type of the local variable but would like to skip references in the annotations. We currently also consider references in an annotation, which is a bug, IMO.

I found the idea quite nice, and I'm sure people dealing with annotations would also be glad to get access to the enclosing IAnnotation directly from a *ReferenceMatch.

In summary:

1. generalize the localElement and otherElements properties of TypeReferenceMatch into a new type ReferenceMatch (extends SearchMatch) and let all *ReferenceMatch types extend this new ReferenceMatch

2. return the innermost IAnnotation as local elements of ReferenceMatches
Comment 1 Frederic Fusier CLA 2007-11-28 03:15:53 EST
Set target as 3.4 as fixing this bug is required to address bug 155013 comment 8 point 3.a)
Comment 2 Philipe Mulet CLA 2008-02-13 08:38:21 EST
Could defer until 3.5 since not super critical. 
Nice to have though for API completeness.
So time permitting for M6.
Comment 3 Jerome Lanneluc CLA 2008-02-13 08:40:55 EST
Bug 209778 should be fixed at the same time as this bug
Comment 4 Frederic Fusier CLA 2008-03-11 11:14:42 EDT
Line 623 of RenameTypeProcessor:
	if (match.getLocalElement() instanceof ILocalVariable) {
relies on the type of the local element...

Change SearchEngine to report the most local element will break it and does not fit the Markus' assumption in this bug description:
"That shouldn't be a problem if getLocalElement() always reports the "most
local" of the local elements..."

I'm currently implementing the prototype of this API change and I can confirm that the '3rd strategy' of refactoring will no longer work at all without a corresponding change in JDT/UI code...

Another remark is about the other elements (getOtherElements()). My assumption is that if we change S.E. to report the most local element in other element, we should also do the same for the other elements. Otherwise they would be an inconsistency...

So, two questions at this stage:
1) Is it OK to change the existing API behavior and break clients who use it?
2) If answer to 1) is YES, is it OK to also change the behavior of getOtherElements() in the same way (and of course also break clients who use it)?
Comment 5 Markus Keller CLA 2008-03-11 13:23:06 EDT
(In reply to comment #4)
> I'm currently implementing the prototype of this API change and I can confirm
> that the '3rd strategy' of refactoring will no longer work at all without a
> corresponding change in JDT/UI code...

Can you give an example where it does not work? I checked this example:

import java.util.List;

public class Ref {
    void doA(Ref ref) {}
    void doB(List<Ref> ref) {}
    void doC(@Tag(Ref.class) Ref ref) {}
    void dontD(@Tag(Ref.class) Object ref) {}
}

@interface Tag {
    Class value();
}

The parameter 'ref' in 'dontD' is currently renamed when I rename type 'Ref' to 'Bla' with updating similar stuff, but it should not be, since the reference to Ref is not in the ILocalVariable but in the IAnnotation. I don't have your implementation to test it, but I think the
    if (match.getLocalElement() instanceof ILocalVariable) ...
should do exactly that.


> Another remark is about the other elements (getOtherElements()). My assumption
> is that if we change S.E. to report the most local element in other element, we
> should also do the same for the other elements. Otherwise they would be an
> inconsistency...

Yes, see bug 209778 and comment 0 > In summary: > 1.


> 1) Is it OK to change the existing API behavior and break clients who use it?
I think yes: TypeReferenceMatch.getLocalElement() says "This *may* be a local variable [..] or a type parameter [..]".
I would read "may" as "can be an ILV, an ITP, or something else...", bend the API a bit, and extend this to also return an IAnnotation if that happens to be the innermost local element.

> 2) If answer to 1) is YES, is it OK to also change the behavior of
> getOtherElements() in the same way (and of course also break clients who use
> it)?
Yes, because Javadoc of getOtherElements() just refers to getLocalElement().
Comment 6 Frederic Fusier CLA 2008-03-18 10:17:45 EDT
Created attachment 92799 [details]
Proposed patch

This patch passes all JDT/Core tests and I'm currently running JDT/UI ones.
It also fixes bug 209778 and so matches the expected behavior described in comment 5 (e.g. does not rename 'ref' in 'dontD')

Markus, Jerome, could you review carefully the changes done in the SearchMatch hierarchy and let me know if the design and the Javadoc description make sense?

Thanks in advance
Comment 7 Frederic Fusier CLA 2008-03-18 11:28:29 EDT
All JDT/UI tests also pass. This confirms the fact that nothing should be broken by this patch :-)
Comment 8 Frederic Fusier CLA 2008-03-18 14:55:38 EDT
Created attachment 92832 [details]
New proposed patch after initial Jerome's review

Herea re the Jerome's remarks after a quick initial review of the first patch:
- no new constructors
- maybe ReferenceMatch should be in internal package
- getLocalElement
   design notes in Javadoc
   should be @since 3.4 (e.g for FieldReferenceMatch)
- setLocalElement's Javadoc makes reference to internal field
- same for setOtherElements
- ReferenceMatch's doc makes reference to "type reference"

We also realized that no annotation can be a local element for fields, local variables and type parameters references. So, I removed the changes done on the corresponding SearchMatch classes.

This new patch should address all these points, it passes all JDT/Core Model and DOM tests. I'll run all JDT/UI tests to verify that everything is still OK...
Comment 9 Jerome Lanneluc CLA 2008-03-19 06:23:17 EDT
(In reply to comment #8)
- design notes still present in TypeReferenceMatch#getLocalElement()
- TODO left in MethodReferenceMatch#getLocalElement()
- same for PackageReferenceMatch
- PackageReferenceMatch#getLocalElement() mentions "method reference"
Comment 10 Markus Keller CLA 2008-03-19 10:03:47 EDT
(In reply to comment #8)
> - maybe ReferenceMatch should be in internal package

Why? It's a useful abstraction, and introducing the APIs get/setLocalElement() in an internal class is confusing and inconvenient for clients. It also makes e.g. setLocalElement(..) inaccessible for clients of MethodReferenceMatch.

> We also realized that no annotation can be a local element for fields, local
> variables and type parameters references. So, I removed the changes done on the
> corresponding SearchMatch classes.

What about references to Num.CONST here?

@Num(number= Num.CONST)
@interface Num {
    public static final int CONST= 42;
    int number();
}

Isn't this a FieldReferenceMatch whose getLocalElement() should return the @Num annotation?

For LocalVariableReferenceMatch and TypeParameterReferenceMatch, I have not found examples where they are referenced inside an annotation, so making them subclass ReferenceMatch is not necessary for this bug (but might be interesting in the future, e.g. to get the enclosing ILocalVariable when the searched local variable is used in the initializer).


Javadocs indeed need some polish. I would be defensive in what you specify for getLocalElement(). The only guarantee should be that the elements are IJavaElements whose getParent() chain eventually leads to the element from getElement(). All the rest should be hints.
Comment 11 Jerome Lanneluc CLA 2008-03-19 10:53:24 EDT
Note I'm not sure what is the value for providing setLocalElement(...). Search matches can be passed to several search participants. If one of them is changing the local element, subsequent participants will get unexpected results.
Comment 12 Markus Keller CLA 2008-03-19 12:03:18 EDT
(In reply to comment #11)
> Note I'm not sure what is the value for providing setLocalElement(...).

All other properties of search matches are settable by clients (including TypeReferenceMatch.setLocalElement(IJavaElement)), so this property should also be settable for consistency. IIRC, this was done to allow clients to create their own search matches or modify existing matches (the Rename refactoring e.g. updates positions in some cases to strip out qualifiers).

> Search matches can be passed to several search participants. If one of them is
> changing the local element, subsequent participants will get unexpected
> results.

I don't understand how that could happen. AFAIK, a SearchParticipant only *generates* search matches.
Comment 13 Jerome Lanneluc CLA 2008-03-19 13:05:01 EDT
(In reply to comment #12)
> (In reply to comment #11)
> > Note I'm not sure what is the value for providing setLocalElement(...).
> 
> All other properties of search matches are settable by clients (including
> TypeReferenceMatch.setLocalElement(IJavaElement)), so this property should also
> be settable for consistency. 
Actually I think this was a mistake. And no one is using them: we didn't find any reference to set*Element() in Ganymede. 

> IIRC, this was done to allow clients to create
> their own search matches or modify existing matches (the Rename refactoring
> e.g. updates positions in some cases to strip out qualifiers).
If there were such clients they could have their own subclasses. 
 
> > Search matches can be passed to several search participants. If one of them is
> > changing the local element, subsequent participants will get unexpected
> > results.
> 
> I don't understand how that could happen. AFAIK, a SearchParticipant only
> *generates* search matches.
Sorry I meant search requestors (e.g. if a search requestor wraps another search requestor). 

Search matches are the result of an operation. It is completely unexpected to make side effects on such results.
Comment 14 Markus Keller CLA 2008-03-19 14:25:32 EDT
(In reply to comment #13)
> Search matches are the result of an operation. It is completely unexpected to
> make side effects on such results.

But it's convenient and performant (saves us from creating a wrapper for every match object or copy everything into new objects of a subclass). And it's not a problem as long as the requestor is not passed on to others (which it usually is not).

Furthermore, it may also make sense for search participants to create their own TypeReferenceMatches, e.g. for some embedded SQL in a String that is known to refer to a Java type name. The SearchMatches are today completely usable in this example, but when clients cannot set all properties, it becomes awkward.
Comment 15 Frederic Fusier CLA 2008-03-19 15:02:47 EDT
(In reply to comment #14)
> 
> But it's convenient and performant (saves us from creating a wrapper for every
> match object or copy everything into new objects of a subclass). And it's not a
> problem as long as the requestor is not passed on to others (which it usually
> is not).
> 
> Furthermore, it may also make sense for search participants to create their own
> TypeReferenceMatches, e.g. for some embedded SQL in a String that is known to
> refer to a Java type name. The SearchMatches are today completely usable in
> this example, but when clients cannot set all properties, it becomes awkward.
> 
I'm not really sure to understand why you (JDT/UI) are so upset by this setter (setLocalElement(...)) inaccessibility on ReferenceMatch although you currently do not use it on TypeReferenceMatch? Do you plan to use it in the near future?
Comment 16 Markus Keller CLA 2008-03-20 07:33:30 EDT
> I'm not really sure to understand why you (JDT/UI) are so upset by this setter
> (setLocalElement(...)) inaccessibility on ReferenceMatch although you currently
> do not use it on TypeReferenceMatch? Do you plan to use it in the near future?

We have no plans to use setLocalElement(...) right now, but I just like clean and consistent APIs. However, I won't die without it. But I will die if ReferenceMatch is not made API. Without that, a client who wants to find matches in annotations would have to write a sermon of "instanceof *ReferenceMatch" tests and also cast to each subtype of ReferenceMatch just to be able to call getLocalElement().
Comment 17 Frederic Fusier CLA 2008-03-20 08:18:02 EDT
(In reply to comment #16)
> > I'm not really sure to understand why you (JDT/UI) are so upset by this setter
> > (setLocalElement(...)) inaccessibility on ReferenceMatch although you currently
> > do not use it on TypeReferenceMatch? Do you plan to use it in the near future?
> 
First, I wanted to apologize reading this again. It looks like I should not have
to use 'upset' as this term is too vague and could make my phrase
tendentious or worst... :-(

I just wanted to mean 'annoyed' and should have to use this term instead...
I wish I was a native English speaker! <g>

> We have no plans to use setLocalElement(...) right now, but I just like clean
> and consistent APIs. However, I won't die without it. But I will die if
> ReferenceMatch is not made API. Without that, a client who wants to find
> matches in annotations would have to write a sermon of "instanceof
> *ReferenceMatch" tests and also cast to each subtype of ReferenceMatch just to
> be able to call getLocalElement().
> 
As, we urgently need to focus today on this API, we agreed to move ReferenceMatch as an API class. _All_ *ReferenceMatch classes will inherit from this abstract class but getLocalElement will ever return null for LocalVariableReferenceMatch and TypeParameterReferenceMatch. setLocalElement will not be accessible on the ReferenceMatch API class but only on TypeReferenceMatch for backward compatibility...

I hope this would be ok for you and that I can implement this today to let you review it before your long week-end ;-)
Comment 18 Markus Keller CLA 2008-03-20 10:02:23 EDT
> [..] upset [..]
No offense taken. I don't care about etiquette here, I only care about APIs ;-)

> _All_ *ReferenceMatch classes will inherit from ReferenceMatch [..]

This of course poses the problem how to specify the API for LocalVariable-/TypeParameterReferenceMatch#getLocalElement(). I would just let the *ReferenceMatch which really implement #getLocalElement() inherit from ReferenceMatch. The others can easily be added later on.

Otherwise, the API would have to tell that it may not work in 3.4 for some targets but would probably be fixed for later releases. Not nice and not too helpful for clients.

> I hope this would be ok for you and that I can implement this today to let you
> review it before your long week-end ;-)

AFAICS in my inbox, my long week-end will not be that long in the end :-/
Comment 19 Frederic Fusier CLA 2008-03-20 10:33:33 EDT
(In reply to comment #18)
> > _All_ *ReferenceMatch classes will inherit from ReferenceMatch [..]
> 
> This of course poses the problem how to specify the API for
> LocalVariable-/TypeParameterReferenceMatch#getLocalElement(). I would just let
> the *ReferenceMatch which really implement #getLocalElement() inherit from
> ReferenceMatch. The others can easily be added later on.
> 

> Otherwise, the API would have to tell that it may not work in 3.4 for some
> targets but would probably be fixed for later releases. Not nice and not too
> helpful for clients.
> 
We were more thinking about a simple implementation and documentation in ReferenceMatch, something like:

public abstract class ReferenceMatch extends SearchMatch {
...
/**
 * Returns the local element of this search match.
 * 
 * @return <code>null</code> if the search match does not have any local
 *     element. Otherwise, look at the subclass of the concrete search match 
 *     to know what Java element could be returned.
 */
public IJavaElement getLocalElement() {
	return null;
}
}
Comment 20 Frederic Fusier CLA 2008-03-21 11:55:39 EDT
Created attachment 93144 [details]
Last proposed patch
Comment 21 Frederic Fusier CLA 2008-03-21 11:59:22 EDT
Jerome already has kindly reviewed this patch, thanks for the time :-)

Markus,
I hope you'll have some time to have a look at it before I release it. I'll plan to do it tomorrow evening, except if you do not agree and shout before...
Comment 22 Markus Keller CLA 2008-03-21 14:23:40 EDT
(In reply to comment #20)

1. Some typos in ReferenceMatch.getLocalElement():
- "inner most" -> "inner-most"
- "the most usal case" -> "usual"
- "<pre> public class X< T extends Test>" -> "X&lt;T extends Test&gt;"


2. InternalReferenceMatch as a superclass of an API class causes awkward API problems: With the patch, an innocent call to TypeReferenceMatch#getLocalElement() is now flagged as "Discouraged access". The best design is not to have inaccessible supertypes of an API class.


3. Issues I found while testing with a breakpoint in NewSearchResultCollector (you can also deal with these in another bug if you want):

public class Test {
    @Tag Test test1, test2, test3;
    void method() {
        @Tag Test local= null;
        @Tag Test local1, local2, local3;
    }
}
@interface Tag {}

* References to type Tag:
Expected (e= getElement(); le= getLocalElement(); oe= getOtherElements()):
- 1: e= test1; le= @Tag (in test1), oe= {@Tag (in test2), @Tag (in test3)}
  => was:                           oe= null
- 2: e= method; le= ILocalVariable local; oe= null
  => was:       le= null
- 3: e= method; le= ILocalVariable local1; oe= {ILV local2, ILV local3}
  => was:       le= null                   oe= null


4. With annotations, there are now also cases where Method-/Field-/PackageReferenceMatch require getOtherElements(). This method should be pulled up into ReferenceMatch. 
Example:

public class TestMethodReference {
    @Annot(clazz = pack.Test.class) int x, y;
}
@interface Annot {
    Class clazz();
}

=> Search for references to 'clazz' should return a MethodReferenceMatch with
     e= x; le= @Annot (in x); oe= {@Annot (in y)}

=> Similar case for FieldReferenceMatch and PackageReferenceMatch (e.g. search for references to 'pack' in example above)
Comment 23 Frederic Fusier CLA 2008-03-21 15:11:57 EDT
(In reply to comment #22)
> 1. Some typos in ReferenceMatch.getLocalElement():
> 
Fixed.
> 
> 2. InternalReferenceMatch as a superclass of an API class causes awkward API
> problems: With the patch, an innocent call to
> TypeReferenceMatch#getLocalElement() is now flagged as "Discouraged access".
> The best design is not to have inaccessible supertypes of an API class.
> 
Perhaps the solution would be to let getLocalElement() on TypeReferenceMatch which simply invokes the super method.

> 
> 3. Issues I found while testing with a breakpoint in NewSearchResultCollector
> (you can also deal with these in another bug if you want):
> 
I'll investigate...
> 
> 4. With annotations, there are now also cases where
> Method-/Field-/PackageReferenceMatch require getOtherElements(). This method
> should be pulled up into ReferenceMatch. 
> Example:
> 
> public class TestMethodReference {
>     @Annot(clazz = pack.Test.class) int x, y;
> }
> @interface Annot {
>     Class clazz();
> }
> 
> => Search for references to 'clazz' should return a MethodReferenceMatch with
>      e= x; le= @Annot (in x); oe= {@Annot (in y)}
> 
> => Similar case for FieldReferenceMatch and PackageReferenceMatch (e.g. search
> for references to 'pack' in example above)
> 
We talk about this case with Jerome and we agreed that it was not necessary as it would be the same annotation (even if the parent is different). Why do you need to have the other local variable in this case?
Comment 24 Markus Keller CLA 2008-03-21 16:04:31 EDT
(In reply to comment #23)
> Perhaps the solution would be to let getLocalElement() on TypeReferenceMatch
> which simply invokes the super method.

Would be a workaround if applied to all subclasses of InternalReferenceMatch, yes. Is it worth the hassle, given that the only "advantage" is that the *ReferenceMatch classes have one special property that is just read-only?

> > 4. With annotations, there are now also cases where
> > Method-/Field-/PackageReferenceMatch require getOtherElements().
[..]
> We talk about this case with Jerome and we agreed that it was not necessary as
> it would be the same annotation (even if the parent is different). Why do you
> need to have the other local variable in this case?

I don't need it, but that's probably because I don't write tooling for annotations. The rationale is the same as for TypeReferenceMatch#getOtherElements(): There, we needed ILocalVariables as other elements because that's the only way for clients to get at these ILocalVariables without building an AST.

One scenario where this would be useful is if someone needs to collect all local variables that are annotated with "@Annot(clazz= pack.Test.class)" with an explicit "class= *". Without MethodReferenceMatch#getOtherElements(), they would not be able to find out about the variable y that's also annotated.

But since the API deadline is approaching quickly, we can also defer point 4.
Comment 25 Frederic Fusier CLA 2008-03-22 06:55:23 EDT
(In reply to comment #24)
> (In reply to comment #23)
> > Perhaps the solution would be to let getLocalElement() on TypeReferenceMatch
> > which simply invokes the super method.
> 
> Would be a workaround if applied to all subclasses of InternalReferenceMatch,
> yes. Is it worth the hassle, given that the only "advantage" is that the
> *ReferenceMatch classes have one special property that is just read-only?
> 
That's right and I do not want to use this workaround on all subclasses.
So, I do prefer rename the method getLocalElement() on InternalReferenceMatch as localElement(), implement it on ReferenceMatch to return null and finally make getLocalElement() calling this protected method. Then, there's no longer warning while calling getLocalElement() from a TypeReferenceMatch outside JDT/Core.

> > > 4. With annotations, there are now also cases where
> > > Method-/Field-/PackageReferenceMatch require getOtherElements().
> [..]
> I don't need it, but that's probably because I don't write tooling for
> annotations. The rationale is the same as for
> TypeReferenceMatch#getOtherElements(): There, we needed ILocalVariables as
> other elements because that's the only way for clients to get at these
> ILocalVariables without building an AST.
> 
> One scenario where this would be useful is if someone needs to collect all
> local variables that are annotated with "@Annot(clazz= pack.Test.class)" with
> an explicit "class= *". Without MethodReferenceMatch#getOtherElements(), they
> would not be able to find out about the variable y that's also annotated.
> 
> But since the API deadline is approaching quickly, we can also defer point 4.
> 
Agreed, let's defer this to 3.5...
Comment 26 Frederic Fusier CLA 2008-03-22 07:52:49 EDT
(In reply to comment #22)
> 3. Issues I found while testing with a breakpoint in NewSearchResultCollector
> (you can also deal with these in another bug if you want):
> 
> public class Test {
>     @Tag Test test1, test2, test3;
>     void method() {
>         @Tag Test local= null;
>         @Tag Test local1, local2, local3;
>     }
> }
> @interface Tag {}
> 
> * References to type Tag:
> Expected (e= getElement(); le= getLocalElement(); oe= getOtherElements()):
> - 1: e= test1; le= @Tag (in test1), oe= {@Tag (in test2), @Tag (in test3)}
>   => was:                           oe= null
> - 2: e= method; le= ILocalVariable local; oe= null
>   => was:       le= null
> - 3: e= method; le= ILocalVariable local1; oe= {ILV local2, ILV local3}
>   => was:       le= null                   oe= null
> 
Here is the result of my investigation:

1) There's a problem with the annotation visit in the compiler. It currently does not visit the annotation although I guess it should.

Philippe, is it OK for you if I modify the traverse(ASTVisitor, BlockScope) methods on Annotation subclasses as follow:

MarkerAnnotation:
public void traverse(ASTVisitor visitor, BlockScope scope) {
	if (visitor.visit(this, scope)) {
		this.type.traverse(visitor, scope);
	}
	visitor.endVisit(this, scope);
}

NormalAnnotation:
public void traverse(ASTVisitor visitor, BlockScope scope) {
	if (visitor.visit(this, scope)) {
		this.type.traverse(visitor, scope);
		if (this.memberValuePairs != null) {
			...
		}
	}
	visitor.endVisit(this, scope);
}

SingleMemberAnnotation:
public void traverse(ASTVisitor visitor, BlockScope scope) {
	if (visitor.visit(this, scope)) {
		this.type.traverse(visitor, scope);
		if (this.memberValue != null) {
			this.memberValue.traverse(visitor, scope);
		}
	}
	visitor.endVisit(this, scope);
}

Null check on this.type does not seem necessary as all constructors senders for these classes provide a non-null value for the type reference...

2) After having fixing the compiler issue + problems with other elements,
I get now:
* References to type Tag:
- 1: e= test1; le= @Tag (in test1), oe= {IF test2, IF test3}
- 2: e= method; le= @Tag (in local); oe= null
- 3: e= method; le= @Tag (in local1); oe= {ILV local2, ILV local3}

Markus, this is slightly different from what you're expected:
a) the objects in the other elements array are ILocalVariable not IAnnotation.
   Report annotations there does not seem necessary as it would be the same
   one with only a different parent => we can directly report the parents
   in this array.
b) The local element for 2) and 3) is (an Annotation. You should not expect
   a ILocalVariable as you're searching for reference to the type Tag...
   Did I miss something here?

If you agree with this results, then point 4) can also be fixed in 3.4 :-). Otherwise, revert the change to currently report null and postpone the discussion about this behavior to 3.5...
Comment 27 Frederic Fusier CLA 2008-03-22 07:54:26 EDT
(In reply to comment #26)
> If you agree with this results, then point 4) can also be fixed in 3.4 :-).
> Otherwise, revert the change to currently report null and postpone the
> discussion about this behavior to 3.5...
> 
Forget this remark, I mixed the points. Point 4) discussion definitely needs to be postponed to 3.5...
Comment 28 Frederic Fusier CLA 2008-03-22 09:40:15 EDT
Created attachment 93191 [details]
Proposed patch fixing comment 22 issues

This new patch includes changes described at comment 25 and comment 26.
It passes all JDT/Core and JDT/UI tests, but... now fails to fix bug 209778 as well.

The key point is other elements returning null or not on comment 22 example 2).
There are 3 possibilities for the object returned by getOtherElements() in this peculiar case:
1) return null, then bug 209778 will be fixed :-)
2) return an array of ILocalVaribale (comment 26 point 2)), then bug 209778 needs
   a change in JDT/UI code to be fixed
3) return an array of IAnnotation, then the fix needs to be done in JDT/Core
   (not trivial => M7)

Personally my preferences order would (obviously) be: first 2), then 1) and 3) at last...
Comment 29 Markus Keller CLA 2008-03-23 06:46:08 EDT
(In reply to comment #28)

Now, the protected ReferenceMatch#localElement() is an API method in subclasses of ReferenceMatch, but it should not be.

> The key point is other elements returning null or not on comment 22 example 2).

Sorry, my examples in comment 22 point 3 were indeed screwed. The local and other references in ex. 2 and 3 should have pointed to IAnnotations, not ILocalVariables.

> There are 3 possibilities for the object returned by getOtherElements() in this
> peculiar case:
> 1) return null, then bug 209778 will be fixed :-)
=> Good for M6, but would not really fix bug 209778.

> 2) return an array of ILocalVaribale (comment 26 point 2)), then bug 209778
> needs
>    a change in JDT/UI code to be fixed
=> I wouldn't do this mixture. 'Local' elements are now defined as the inner-most elements, and it would be strange if getOtherElements() would not return inner-most elements now (the existing Javadoc of TypeReferenceMatch explicitly talks about local elements). Better to have null for M6.

> 3) return an array of IAnnotation, then the fix needs to be done in JDT/Core
>    (not trivial => M7)
=> The way to go for M7. 
Comment 30 Frederic Fusier CLA 2008-03-23 07:57:26 EDT
(In reply to comment #29)
> 
> Now, the protected ReferenceMatch#localElement() is an API method in subclasses
> of ReferenceMatch, but it should not be.
> 
I think there's no perfect solution here. With this one, I agree that client can call localElement(). So, I suggest to say that ReferenceMatch is  not intended to be subclassed by clients and then, they will get a "Discouraged access" warning telling them they should not use this method if they call it in a subclass of *ReferenceMatch. Would it be acceptable?

> > The key point is other elements returning null or not on comment 22 example 2).
> 
> Sorry, my examples in comment 22 point 3 were indeed screwed. The local and
> other references in ex. 2 and 3 should have pointed to IAnnotations, not
> ILocalVariables.
> 
OK, I'll implement solution 1) for M6 and we see what we will do for M7...
Comment 31 Frederic Fusier CLA 2008-03-23 12:13:32 EDT
Created attachment 93215 [details]
Last proposed patch for M6

This last patch includes the last comments remarks:
1) Warn clients that ReferenceMatch is not intended to be subclassed
2) comment 28 solution 1)
Comment 32 Frederic Fusier CLA 2008-03-23 12:22:20 EDT
I released the last patch for 3.4M6 in HEAD stream to have it in today's warm-up build. We'll tune it next week if necessary...
Comment 33 Eric Jodet CLA 2008-03-26 05:00:10 EDT
Verified for 3.4M6 using build I20080324-1300