Community
Participate
Working Groups
java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.resolveTypeFor(SourceTypeBinding.java:1395) at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.fields(SourceTypeBinding.java:711) at org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding.availableFields(ReferenceBinding.java:176) at org.eclipse.jdt.core.dom.TypeBinding.getDeclaredFields(TypeBinding.java:224) [snip 8< my code below] In a CompilationParticipant, I obtain the CU for the compiled file by means of ICompilationUnit cu = (ICompilationUnit) JavaCore.create(javaFile /* IFile */); ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setProject(cu.getJavaProject()); parser.setIgnoreMethodBodies(false); IType[] allTypes = getAllTypes(cu); IBinding[] bindings = parser.createBindings(allTypes, null); with private IType[] getAllTypes(ICompilationUnit compilationUnit) throws JavaModelException { List<IType> result = new ArrayList<IType>(4); for (IType type : compilationUnit.getTypes()) { result.add(type); addAllMemberTypes(type, result); } return result.toArray(new IType[result.size()]); } private void addAllMemberTypes(IMember container, List<IType> result) throws JavaModelException { for (IJavaElement child : container.getChildren()) { if (child instanceof IMember) { if (child instanceof IType) { result.add((IType) child); } addAllMemberTypes((IMember) child, result); } } } For the following two files in the default package of an IJavaProject .. == public class Outer { public class Inner extends SuperClass { public Inner(String s) { } } } == public class SuperClass { String f; } == .. I can correctly find two ITypeBindings if Outer.java is compiled by my participant. I get a binding for Outer and another one for Outer$Inner. As soon as I try to navigate to the supertype of Inner and query 'SuperClass' for its fields, I get the exception above. Is there something that I have to keep in mind when dealing with the parser and stuff in a CompilationParticipant?
Preliminary answer from locking at your snippets and the implementation in SourceTypeBinding: - while compiling Outer we've touched SuperClass to the degree that we created the type binding and connected it (supers, members), we haven't yet fully resolved 'f' (it was not requested). - at the end of this compilation SourceTypeBinding.scope is discarded - when later outside the compilation proper you navigate to SuperClass and ask for its 'fields()', each of these has to resolve its type which it does using the scope -> NPE Do we really really need the scope? Without it we 1. cannot find the compiler options to determine the sourceLevel 2. cannot find the corresponding TypeDeclaration 3. report any errors using the typical scope.problemReporter() idiom. 1&3 could be circumvented somehow, but for 2 I see no alternative. I don't think the API makes any promises about referenced bindings which are not *contained* in allTypes.
(In reply to comment #1) > I don't think the API makes any promises about referenced bindings which are > not *contained* in allTypes. That's suprising. IMHO it would not make much sense to restrict the resolution of bindings to the initially requested data. This would raise the question: How would I know which bindings are valid and for which of those transitive bindings do I have to re-request the resolution. Is there even a method that tells me about the internal state of a binding, e.g. if it's valid / resolved or not? Can I somehow trigger further resolution?
Disclaimer: I did not invent any of these API, I'm only interpreting what I see. (In reply to comment #2) > (In reply to comment #1) > > I don't think the API makes any promises about referenced bindings which are > > not *contained* in allTypes. > > > That's suprising. IMHO it would not make much sense to restrict the > resolution of bindings to the initially requested data. I can understand your surprise from a client's p.o.v., but from an implementation p.o.v. guaranteeing fully resolved everything would mean the ASTParser can only convert entire universes, never just one class at a time. Mind you: the primary responsibility of the ASTParser is to create DOM AST, which it does completely. Providing bindings as a side-effect is - a welcome *side-effect*. > This would raise the > question: How would I know which bindings are valid and for which of those > transitive bindings do I have to re-request the resolution. Very good question. I believe the following can be taken as a rule of thumb: - you get bindings for all directly referenced types plus their supers - members of your supers will have bindings, specifically: - signatures of methods are resolved - field types are not guaranteed (as you are experiencing) - types used in method bodies are not guaranteed - members of referenced types not in your set of compilation units can be unresolved. > Is there even a > method that tells me about the internal state of a binding, e.g. if it's > valid / resolved or not? Can I somehow trigger further resolution? Hm, for the compiler bindings we have the Unresolved* variants. Right now I don't know any public API that would expose this info, although I agree there should be some.
FYI: bug 392333 :) With that, do you agree to close this as WORKSFORME, since your trying things that are not guaranteed by the API? Would a more specific exception help (making this limitation explicit)?
I'd prefer a more meaningful exception instead of the NPE, e.g. a JavaModelException or IllegalStateException with a reasonable message. Is that possible?
The exception is simply logged, but it doesn't stop the application. What would be needed to "fix" this issue is the ability to create scopes on the fly to be able to resolve more bindings. In the past, we use to keep scopes as long as the whole tree was not discarded, but this was holding to too much memory. This is why we now remove all scopes before returning the tree after all bindings have been resolved. Creating scopes on the fly as its own set of issues that we never had time to work on.
You're right, the exception did not surface to the user. My compile participant simply stopped working - silently. It took some time to figure out what was wrong :-( Therefore a more helpful entry in the log is greatly appreciated.
I know the pains of uninformative error messages so let's see what we can do: - TypeBinding.getDeclaredFields() is API so we cannot add exceptions -> we can only log a better message - SourceTypeBinding, the source of the problem is part of ecj and must not depend on any classes from model or other packages -> we need to invent a new Exception - SourceTypeBinding.scope is accessed all over the place, but we might cut this down to to a meaningful list like this: - getMethods(char[]) - methods() - resolveTypeFor(FieldBinding) - resolveTypesFor(MethodBinding) - sourceEnd() - sourceStart() - storedAnnotations(boolean) (?) This should be the intersection of - dereferences scope - could potentially be called from DOM Srikanth: I'm marking this for review even before I have a patch to ask your opinion on adding specific error handling along the lines in this comment.
(In reply to comment #6) > ... In the past, we use to keep > scopes as long as the whole tree was not discarded, but this was holding to > too much memory. This is why we now remove all scopes before returning the > tree after all bindings have been resolved. Does this mean by proposing bug 392333 I'm going in circles, or could this make sense as an off-by-default option?
I found this while skimming through my review requests: (In reply to comment #8) > Srikanth: I'm marking this for review even before I have a patch to ask your > opinion on adding specific error handling along the lines in this comment.
(In reply to Stephan Herrmann from comment #10) > I found this while skimming through my review requests: > > (In reply to comment #8) > > Srikanth: I'm marking this for review even before I have a patch to ask your > > opinion on adding specific error handling along the lines in this comment. I am sorry, this somehow slipped my radar and the reminder too. Apologies. How about not clearing the scopes if there is a compilation participant ?
I just noticed that during our test runs, org.eclipse.jdt.core.tests.dom.BatchASTCreationTests.test070 throws this exception to apparently no deleterious end. java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.resolveTypeFor(SourceTypeBinding.java:1684) at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.fields(SourceTypeBinding.java:883) at org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding.availableFields(ReferenceBinding.java:223) at org.eclipse.jdt.core.dom.TypeBinding.getDeclaredFields(TypeBinding.java:244) at org.eclipse.jdt.core.tests.dom.BatchASTCreationTests.test070(BatchASTCreationTests.java:1661) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at junit.framework.TestCase.runTest(TestCase.java:176) at junit.framework.TestCase.runBare(TestCase.java:141) at junit.framework.TestResult$1.protect(TestResult.java:122) at junit.framework.TestResult.runProtected(TestResult.java:142) at junit.framework.TestResult.run(TestResult.java:125) at junit.framework.TestCase.run(TestCase.java:129) at junit.framework.TestSuite.runTest(TestSuite.java:255) at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.runTest(SuiteOfTestCases.java:104) at junit.framework.TestSuite.run(TestSuite.java:250) at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.superRun(SuiteOfTestCases.java:88) at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$1.protect(SuiteOfTestCases.java:76) at junit.framework.TestResult.runProtected(TestResult.java:142) at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.run(SuiteOfTestCases.java:85) at junit.framework.TestSuite.runTest(TestSuite.java:255) at junit.framework.TestSuite.run(TestSuite.java:250) at junit.framework.TestSuite.runTest(TestSuite.java:255) at junit.framework.TestSuite.run(TestSuite.java:250) at junit.framework.TestSuite.runTest(TestSuite.java:255) at junit.framework.TestSuite.run(TestSuite.java:250) at junit.framework.TestSuite.runTest(TestSuite.java:255) at junit.framework.TestSuite.run(TestSuite.java:250) at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:131) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62) at org.eclipse.pde.internal.junit.runtime.CoreTestApplication.run(CoreTestApplication.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at org.eclipse.equinox.internal.app.EclipseAppContainer.callMethodWithException(EclipseAppContainer.java:587) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:198) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:382) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:236) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:648) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:603) at org.eclipse.equinox.launcher.Main.run(Main.java:1465) at org.eclipse.equinox.launcher.Main.main(Main.java:1438)
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.
Significant work in this area had started in bug 150657, where I dropped the ball two years ago.