Community
Participate
Working Groups
20040512 for the following code get the var binding of BUNDLE_NAME and do 'getContantValue' public class Accessor { private static final String BUNDLE_NAME = "test.test";//$NON-NLS-1$ public static String getString(String s) { return ""; } } java.lang.NullPointerException at java.lang.Throwable.<init>(Throwable.java) at java.lang.Throwable.<init>(Throwable.java) at java.lang.NullPointerException.<init>(NullPointerException.java:60) at org.eclipse.jdt.core.dom.VariableBinding.getConstantValue(VariableBinding.java:196) at org.eclipse.jdt.internal.corext.refactoring.nls.NLSInfo.getResourceBundle(NLSInfo.java:95) at org.eclipse.jdt.internal.corext.refactoring.nls.NLSInfo.getAccessorClassInfo(NLSInfo.java:73) at org.eclipse.jdt.internal.corext.refactoring.nls.NLSHolder.create(NLSHolder.java:48) at org.eclipse.jdt.ui.tests.nls.NLSSourceModifierTest.testFromTranslatedToNotTranslated(NLSSourceModifierTest.java:202) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:41) at java.lang.reflect.Method.invoke(Method.java:386) at junit.framework.TestCase.runTest(TestCase.java:154) at junit.framework.TestCase.runBare(TestCase.java:127) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:118) at junit.framework.TestSuite.runTest(TestSuite.java:208) at junit.framework.TestSuite.run(TestSuite.java:203) at junit.extensions.TestDecorator.basicRun(TestDecorator.java:22) at junit.extensions.TestSetup$1.protect(TestSetup.java:19) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.extensions.TestSetup.run(TestSetup.java:23) at junit.framework.TestSuite.runTest(TestSuite.java:208) at junit.framework.TestSuite.run(TestSuite.java:203) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:422) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:306) at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:30) at org.eclipse.pde.internal.junit.runtime.UITestApplication$1.run(UITestApplication.java:90) at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35) at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:106) at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:2702) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2394) at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:1353) at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:1324) at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:243) at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:141) at org.eclipse.ui.internal.ide.IDEApplication.run(IDEApplication.java:90) at org.eclipse.pde.internal.junit.runtime.UITestApplication.run(UITestApplication.java:33) at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformActivator.java:298) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:249) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:126) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:41) at java.lang.reflect.Method.invoke(Method.java:386) at org.eclipse.core.launcher.Main.basicRun(Main.java:269) at org.eclipse.core.launcher.Main.run(Main.java:722) at org.eclipse.core.launcher.Main.main(Main.java:706)
I will investigate.
I cannot reproduce.
The right test case is: package test0554; public class A { private static final String BUNDLE_NAME = "test.test";//$NON-NLS-1$ public static String getString(String s) { return ""; } } package test0554; import test0554.A; public class B { public static String foo() { return A.getString("xx"); } } In B, get the variable binding for BUNDLE_NAME through the type binding of A using the getDeclaringFields() method. In this case, the constant for the field BUNDLE_NAME is not initialized and it is null. I will add a null check. Philippe, do we have a way to initialize this field binding?
The test cases I added need to update in case we can get the constant value.
In case B is like this: public class B { public static String foo() { return A.BUNDLE_NAME; } } And BUNDLE_NAME is changed to be public then you can get the constant value using the same call. So it is inconsistent when the constant is available and when it is not.
This is a kind of lazy initialization for us. In the case in comment 3, the field is not directly referenced in B. Therefore its constant is not initialized. The workaround is to get the declaration for A and get the field binding from there. Then it will be resolved and the constant won't be null anymore. Jim, this kind of behavior should be clarified in the specs. If we want to be able to get such field at any time, then we have to keep the scopes around and this would increase the footprint. Once the specs are updated, this bug can be closed. I already added the null check.
The notion of bindings that the AST API provides are supposed to be accurate at the time the compilation unit was anaylzed. Whether a variable binding has a constant value or not should be independent of whether the field is public or private. So I believe this should be considered a bug in the implementation. Olivier, you mention that the implementation currently does this lazily and that fixing it would require keeping around scope objects. Bindings, by their nature, already have a significant footprint (as the spec points out). How much bigger would these scope objects make it? Can you see any alternatives, such as computing the value of constant fields eagerly?
I don't know exactly how much bigger it would be, but keeping the whole scope and name environment around might be expensive. I don't see any other way to fix this, because right now we cannot create scopes on demand and once they are removed, no further resolution can be performed.
Reconsider post 3.0.
reopening
Reconsidering for 3.2. Will release changes to move the reference lazy resolution directly into the binding. So as long as the scope is alive, the constant may be computed lazily. Fixed. Tuned affected tests: ASTConverterTest2#test0554 ASTConverterTestAST3_2#test0554
*** Bug 117018 has been marked as a duplicate of this bug. ***
Verified for 3.2 M4 using build I20051212-0010
Created attachment 32755 [details] Patch against R3_1_maintenance branch just in case we want to backport the fix to the R3_1_maintenance branch ...
Created attachment 32762 [details] Updated tests against R3_1_maintenance branch