Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 371975

Summary: No way to determine whether context is static from ITypeBinding
Product: [Eclipse Project] JDT Reporter: Jacek Sieka <arnetheduck>
Component: CoreAssignee: Stephan Herrmann <stephan.herrmann>
Status: CLOSED WONTFIX QA Contact:
Severity: normal    
Priority: P3 CC: amj87.iitr, srikanth_sankaran, stephan.herrmann
Version: 3.8   
Target Milestone: 4.11 M3   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Jacek Sieka CLA 2012-02-18 12:39:00 EST
Build Identifier: M20110909-1335

For an anonymous type declared in a class/instance initializer, there's no way to tell if it has a reference to its context or not. For types declared in methods or types, getDeclaringMethod/getDeclaringClass modifiers tell if the type has a reference to its enclosing context (this), but for those declared in the initializer, there's no way to tell..

Consider:
class X {
static Object o;
static {
 o = new Object { }
}

Object o2;
{
o2 = new Object() { }
}
}

The synthesized constructor for o2 needs an extra "this" argument, o doesn't but there's no way to tell from the ITypeBindings of each anonymous type.

Reproducible: Always
Comment 1 Ayushman Jain CLA 2012-02-20 04:56:20 EST
I don't see any difference whther I declare an anonymous type inside or outside the initializer. The declaring class info is available to me from all places.

I'm using build 3.8M5.
Perhaps you can provide the code which you use to get the modifiers and I can try on M5. Or is there something I'm missing?
Comment 2 Jacek Sieka CLA 2012-02-20 05:02:11 EST
The problem is that you see no difference =)

o2 will contain a reference to its enclosing X instance while o will not, but from the respective ITypeBinding:s of the two anonymous classes there's no way to tell.

Say you are traversing the AST and stumble upon an AnonymousClassDeclaration for the above code - there's no way do distinguish between the two cases looking at the resolved type binding, even though one is "static" in the sense that it has no reference to X. For types declared in methods or classes directly, you can determine this by checking whether the binding or method is static.
Comment 3 Jacek Sieka CLA 2012-02-20 05:05:51 EST
...whether the *type* or method is static.
Comment 4 Jacek Sieka CLA 2012-02-20 05:10:54 EST
For the record, I'm working on a code generator that needs to know if the generated constructor of the anonymous type will have an implicit "this" parameter or not.
Comment 5 Srikanth Sankaran CLA 2012-02-20 06:41:08 EST
(In reply to comment #2)
> The problem is that you see no difference =)
> 
> o2 will contain a reference to its enclosing X instance while o will not, but
> from the respective ITypeBinding:s of the two anonymous classes there's no way
> to tell.

o2 is a plain field of X and not an object of an inner type of X, why would
it have a "reference to its enclosing X instance" ??

Am I overlooking something here ?
Comment 6 Srikanth Sankaran CLA 2012-02-20 07:02:05 EST
> (In reply to comment #2)
> o2 is a plain field of X and not an object of an inner type of X, why would
> it have a "reference to its enclosing X instance" ??

Never mind. I understand what you are trying to say, I'll poke around
to see if this is discernible.
Comment 7 Jacek Sieka CLA 2012-02-20 14:35:23 EST
Here's the workaround I've been using, but it uses the dicouraged org.eclipse.jdt.internal.core.Initializer:

	public static boolean outerStatic(ITypeBinding tb) {
		if (tb.isLocal() && tb.getDeclaringMethod() == null) {
			IJavaElement je = tb.getJavaElement();
			while (je != null && !(je instanceof Initializer)) {
				je = je.getParent();
			}

			if (je instanceof Initializer) {
				try {
					return Flags.isStatic(((Initializer) je).getFlags());
				} catch (JavaModelException e) {
					throw new Error(e);
				}
			}
		}

		return tb.isLocal() ? tb.getDeclaringMethod() != null
				&& Modifier.isStatic(tb.getDeclaringMethod().getModifiers())
				: Modifier.isStatic(tb.getDeclaringClass().getModifiers());
	}
Comment 8 Stephan Herrmann CLA 2012-02-20 18:08:40 EST
(In reply to comment #7)
> Here's the workaround I've been using, but it uses the dicouraged
> org.eclipse.jdt.internal.core.Initializer:

What's wrong with the public interface org.eclipse.jdt.core.IInitializer
instead of the internal class? 
:)
Comment 9 Srikanth Sankaran CLA 2012-02-20 23:18:27 EST
Jacek, please confirm if you are able to tweak your workaround to
use only public APIs as Stephan alludes to in comment# 8.

If yes, this can be closed as WORKSFORME.

getDeclaringMethod returning null for the initializer case is the
documented behavior. Materializing a handle to <init>, <clinit> is not
readily doable at the point of conversion AFAICS.
Comment 10 Jacek Sieka CLA 2012-02-21 16:50:01 EST
Heh, it's wrong because I didn't see it =)

I can confirm that my workaround works with the suggested public API, but I would still ask you to consider this for a future release - as we both agree, my code is a workaround - it involves a completely different API. ITypeBinding already has getDeclaringClass and getDeclaringMethod - for completeness it I think it would make sense with a getDeclaringInitializer to cover AFAIR all places where a type can be declared.

This is also related to https://bugs.eclipse.org/bugs/show_bug.cgi?id=369848 where it would be nice if other synthetics were available.
Comment 11 Eclipse Genie CLA 2019-02-08 12:05:43 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 12 Stephan Herrmann CLA 2019-02-08 18:13:01 EST
I hold that the use case is fairly uncommon and a solution using existing public API exists, hence closing.