Community
Participate
Working Groups
Build Identifier: 20100617-1415 I got the following NullPointerExpception when trying to synchronize on the instance of an outer class inside an anonymous inner-class that was created in side a static method: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.ClassFile.traverse(ClassFile.java:7655) at org.eclipse.jdt.internal.compiler.ClassFile.completeCodeAttribute(ClassFile.java:1621) at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.generateCode(AbstractMethodDeclaration.java:245) at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.generateCode(AbstractMethodDeclaration.java:179) at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.generateCode(TypeDeclaration.java:542) at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.generateCode(TypeDeclaration.java:585) at org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression.generateCode(QualifiedAllocationExpression.java:173) at org.eclipse.jdt.internal.compiler.ast.Expression.generateCode(Expression.java:601) at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.generateCode(AbstractMethodDeclaration.java:232) at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.generateCode(AbstractMethodDeclaration.java:179) at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.generateCode(TypeDeclaration.java:542) at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.generateCode(TypeDeclaration.java:611) at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.generateCode(CompilationUnitDeclaration.java:361) at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1187) at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:681) at org.eclipse.jdt.core.dom.ASTParser.internalCreateAST(ASTParser.java:1175) at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:801) at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider$1.run(ASTProvider.java:543) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42) at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.createAST(ASTProvider.java:536) at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.getAST(ASTProvider.java:479) at org.eclipse.jdt.ui.SharedASTProvider.getAST(SharedASTProvider.java:126) at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.getOverrideIndicators(OverrideIndicatorLabelDecorator.java:161) at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.computeAdornmentFlags(OverrideIndicatorLabelDecorator.java:136) at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.decorate(OverrideIndicatorLabelDecorator.java:273) at org.eclipse.ui.internal.decorators.LightweightDecoratorDefinition.decorate(LightweightDecoratorDefinition.java:269) at org.eclipse.ui.internal.decorators.LightweightDecoratorManager$LightweightRunnable.run(LightweightDecoratorManager.java:81) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42) at org.eclipse.ui.internal.decorators.LightweightDecoratorManager.decorate(LightweightDecoratorManager.java:365) at org.eclipse.ui.internal.decorators.LightweightDecoratorManager.getDecorations(LightweightDecoratorManager.java:347) at org.eclipse.ui.internal.decorators.DecorationScheduler$1.ensureResultCached(DecorationScheduler.java:371) at org.eclipse.ui.internal.decorators.DecorationScheduler$1.run(DecorationScheduler.java:331) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54) Reproducible: Always Steps to Reproduce: 1. create a new java class ("Test") 2. create a static method ("main") 3. create a local final variable ("final boolean x = true"); 4. create a new anonymous or named innerclass ("new Runnable(){}") 5. create a method ("run") 6. add a synchronize-block and synchronize on the instanceof the outer class ("synchronize (Test.this) {}") 7. access the final variable inside the synchronized block ("System.out.println(x);") Complete file: package ch.actifsource.test; public class Test { public static void test() { final boolean x = true; new Runnable() { @Override public void run() { synchronized (Test.this) { System.out.println(x); } } }; } }
Reproduced. Working on it.
The problem occurs only in 1.6 mode. In 1.5, the compiler error is properly reported and the compilation aborted.
The problem comes from that we tag the outer most method when the problem is detected, but we check the current method (field ignoreFurtherInvestigation) to find out if we should stop the current code generation. This is inconsistent as we detect a problem, but we let the code generation of the current method to proceed.
Created attachment 178645 [details] Proposed fix + regression tests I made some cleanups in the tests at the same time. So to review, please focus more on the changes in the compiler than the tests themselves. I try to understand why we are always used the outermost method scope to report the problem. I think we should always report the problem on the inner most method as this is the one that is checked for the ignoreFurtherInvestigation value.
Srikanth, please review.
Created attachment 178650 [details] Proposed fix + regression tests Same patch with updated copyrights.
Released for 3.7M2. Updated all existing regression tests and added new regression test in: org.eclipse.jdt.core.tests.compiler.regression.StackMapAttributeTest#test047
Verified for 3.7M2 using build I20100914-0100
Looks good.