Bug 212100 - [dom] Can't create binding to inner class
Summary: [dom] Can't create binding to inner class
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.4 M5   Edit
Assignee: Frederic Fusier CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-12-05 21:20 EST by Walter Harley CLA
Modified: 2008-03-12 16:51 EDT (History)
4 users (show)

See Also:
jerome_lanneluc: review+


Attachments
test case (2.21 KB, patch)
2007-12-05 21:23 EST, Walter Harley CLA
no flags Details | Diff
test case #2 (2.49 KB, patch)
2007-12-11 21:45 EST, Walter Harley CLA
no flags Details | Diff
Proposed patch (5.71 KB, patch)
2008-02-01 10:14 EST, Frederic Fusier CLA
no flags Details | Diff
Better patch (6.71 KB, patch)
2008-02-04 12:52 EST, 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 Walter Harley CLA 2007-12-05 21:20:17 EST
I call ASTParser.createASTs, passing in a compilation unit for a class 'X' containing a nested class 'Y', and asking for the binding to java.lang.Object.  Then, within the ASTRequestor.acceptBinding() callback, I use createBindings() to request a binding for the nested type.  I get back a null. 

I'm not sure if this is *supposed* to work, but there's nothing saying it shouldn't (unlike for local elements in acceptAST callbacks, which are documented to not work).

Under the covers, the problem seems to be that in BindingKeyResolver.getCompilationUnitDeclaration(), the SourceTypeBinding obtained for the outer type has a null scope.  This causes the method to return null, which ultimately causes a failure in accessing a binding to the inner type.  When the outer type binding is first created during compilation, its scope is properly set.  However, it then gets nulled out in CompilationUnitDeclaration.cleanUp(), called from CompilationUnitResolver *before* requestor.acceptResult() (where my code takes place) is called.

This occurs in Eclipse 3.2.2, 3.3.1, and HEAD.

Should this work?
Comment 1 Walter Harley CLA 2007-12-05 21:23:38 EST
Created attachment 84583 [details]
test case

Test case demonstrating the problem.  Note the lines commented with "this will make the test fail" or "this would make the test pass"; these change what binding is being requested.
Comment 2 Philipe Mulet CLA 2007-12-06 02:45:06 EST
After scopes got cleaned up, little is expected to work in lazy fashion... need to investigated whether the binding shouldn't have been created earlier on.

Comment 3 Walter Harley CLA 2007-12-06 03:09:41 EST
At present, the Java 5 version of APT always works this way: it calls createASTs() with the compilation unit being processed but only requests java.lang.Object, and then requests additional bindings as needed by the annotation processor from inside the acceptBinding() callback.  See BuildEnv in apt.core for details, and note that AbstractCompilationEnv.getTypeBindingFromKey() overrides BaseProcessorEnv.getTypeBindingFromKey().

I am not totally sure why it was done that way, but a comment in BuildEnv mentions the need to deal with the "batch mode" case where a processor is given all the annotated files at once.

If this shouldn't be relied upon, I can imagine two workarounds.  The first is to do an additional createASTs() whenever we get a null binding, to see if by asking for a specific binding key we can be successful.  Disadvantages are that it is a performance hit, and more importantly, it triggers the "multiverse" problem where bindings from different parse pipelines are not comparable.

The second workaround would be to always ask for bindings for all the types we are compiling, in addition to java.lang.Object, in the outermost call to createASTs().  But I don't think this would work, because I think we can't anticipate what classes a processor will request bindings for.  We could be processing unit Z when the processor asks for a binding for X$Y.
Comment 4 Philipe Mulet CLA 2007-12-11 12:26:46 EST
Maybe something to backport to 3.3.x and 3.2.x if easy.
Comment 5 Walter Harley CLA 2007-12-11 21:45:53 EST
Created attachment 85022 [details]
test case #2

Here is a test case that illustrates the same problem differently.  Given two classes X and Z, each with inner classes, I create a parser and ask it to parse both and give me bindings for both.  The acceptBinding() callback will thus be called first for X and then for Z.  Within the callback I try to create bindings for X, X.Y, Z, and Z.W.  This works when accepting the X binding, but fails when accepting the Z binding.
Comment 6 Frederic Fusier CLA 2008-02-01 10:14:53 EST
Created attachment 88560 [details]
Proposed patch

A definitely naive patch which simply moves the compilation units declaration clean-up at the end of the CompilationUnitResolver.resolve(...) method instead of doing it inside the loop.

This makes the two tests green but may have an impact on performance as memory will not be released until the end of the method. I know this could not be done for builder or search resolving loop as it may have a large number of compilation units in the given array, but my feeling would be that for DOM ASTParser, it should not be the case...

Olivier, Philippe, your review on this proposal is mandatory and some other hints if this solution wouldn't be acceptable, TIA
Comment 7 Jerome Lanneluc CLA 2008-02-01 13:09:36 EST
Unfortunately the main client of this API is refactoring and they rely on us releasing the memory early as a fair amount of compilation units can be analyzed at the same time.
Comment 8 Frederic Fusier CLA 2008-02-02 10:10:00 EST
(In reply to comment #7)
> Unfortunately the main client of this API is refactoring and they rely on us
> releasing the memory early as a fair amount of compilation units can be
> analyzed at the same time.
> 
So, perhaps could we do the clean-up at the end only if there's not too much CUs to resolve (in the 2 test cases there are only one and two CUs).

The other possibility may be to add a specific option for this behavior on the ASTParser and warn the clients that using it may imply high memory usage...
Comment 9 Frederic Fusier CLA 2008-02-04 12:52:41 EST
Created attachment 88801 [details]
Better patch

Better patch after having discussed with Jerome. This patch simply fixes how the BindingKeyResolver get type bindings for member types...
Comment 10 Frederic Fusier CLA 2008-02-04 12:53:14 EST
Jerome, please review, thanks
Comment 11 Jerome Lanneluc CLA 2008-02-04 12:58:28 EST
Patch looks good.
Comment 12 Frederic Fusier CLA 2008-02-05 11:01:17 EST
Better patch released for 3.4M5 in HEAD stream.
Comment 13 Frederic Fusier CLA 2008-03-07 03:42:30 EST
Walter, could you set this bug as VERIFIED if you agree that it's fixed now?
TIA