Bug 340691

Summary: Syntax error leads to ClassCastException in ASTConverter
Product: [Eclipse Project] JDT Reporter: Markus Keller <markus.kell.r>
Component: CoreAssignee: Ayushman Jain <amj87.iitr>
Status: VERIFIED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: Olivier_Thomann, srikanth_sankaran
Version: 3.7   
Target Milestone: 3.7 M7   
Hardware: PC   
OS: Windows 7   
Whiteboard:
Attachments:
Description Flags
proposed fix
none
proposed fix + tests none

Description Markus Keller CLA 2011-03-22 13:22:15 EDT
HEAD

Have this CU with syntax errors:

package xy;
public class Try {
    public static void main(String[] args) {
        synchronized
        new Thread() {
            public void run() {
            }
        }.start();
        
        for (int i= 0; i < 10; i++) {
            System.out.println("batch " + i);
            for (int j= 0; j < 1000*1000*1000; j++) {
                new Integer(1);
            }
        }
    }
}


The ASTParser doesn't really like this:

Error
Tue Mar 22 18:19:44 CET 2011
Error in JDT Core during AST creation

java.lang.ClassCastException: org.eclipse.jdt.core.dom.EnumDeclaration cannot be cast to org.eclipse.jdt.core.dom.TypeDeclaration
	at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:2430)
	at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:532)
	at org.eclipse.jdt.core.dom.ASTConverter.buildBodyDeclarations(ASTConverter.java:183)
	at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:2636)
	at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:1218)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.convert(CompilationUnitResolver.java:289)
	at org.eclipse.jdt.core.dom.ASTParser.internalCreateAST(ASTParser.java:1201)
	at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:801)
	at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider$1.run(ASTProvider.java:544)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.createAST(ASTProvider.java:537)
	at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.getAST(ASTProvider.java:480)
	at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.getAST(ASTProvider.java:470)
	at org.eclipse.jdt.ui.SharedASTProvider.getAST(SharedASTProvider.java:127)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup.calculateASTandInform(SelectionListenerWithASTManager.java:170)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$3.run(SelectionListenerWithASTManager.java:155)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Comment 1 Olivier Thomann CLA 2011-03-22 22:09:50 EDT
The synchronized leads to an empty enum type that looks like this:
synchronized enum $missing$ {
  $missing$() {
    super();
  }
  <clinit>() {
  }
}
So it blows up. I am investigating.
Comment 2 Olivier Thomann CLA 2011-03-23 09:57:27 EDT
At this stage, the best we can do is to prevent the exception. The recovery is doing a poor job at getting a tree for the method body in this case.
So we can tag some nodes as MALFORMED.
The resulting tree is not really usable for refactoring as the only statement recovered in this method body is the synchronized keyword. Everything else is ignored after the syntax error.

What AST would you expect in this case ?
Comment 3 Markus Keller CLA 2011-03-23 15:49:29 EDT
Simplified example:

public class Try {
    public static void main(String[] args) {
        synchronized
        new Object();
    }
}


(In reply to comment #2)
> What AST would you expect in this case ?

Ideally one where just the bad keyword is removed or recovered (similar to when I use 'void' or 'synchronizedXXX' instead). If that's too much work, an empty body (MALFORMED Block with no statements) is also fine.

Note that synchronized is not the only keyword causing trouble here.
public protected private static final strictfp etc. have the same problem.
Comment 4 Olivier Thomann CLA 2011-04-05 09:33:13 EDT
Ayushman, please try to see if there is a better way to recover from the synchronized modifier alone.
If it possible to prevent the CCE, but we should see if there is a better way to recover first.
Comment 5 Ayushman Jain CLA 2011-04-12 15:37:46 EDT
Created attachment 193087 [details]
proposed fix

This happens in the recovery because scope trial succeeds for the rule EnumHeaderName ::= Modifiersopt 'enum' Identifier (since 'synchronized', 'private', 'strictfp' etc are all modifiers), which is more permissive than it should be. Yet, there's no other option as well. 

The attached patch just makes sure that if the recovery, specifically the statements recovery finds a recovered enum declaration, it does not add it as a child to the recovered elements. The normal recovery will still find enums when they're declared in the usual correct manner.

Olivier, what do you think about this approach? I'll add test cases if you approve.
Comment 6 Olivier Thomann CLA 2011-04-12 15:46:23 EDT
I like the approach. I think it would even be better if this rule is not considered at all for the recovery as the suggestion for the syntax error is misleading. I am not sure if this is really doable.
Comment 7 Ayushman Jain CLA 2011-04-12 15:51:52 EDT
(In reply to comment #6)
> I like the approach. I think it would even be better if this rule is not
> considered at all for the recovery as the suggestion for the syntax error is
> misleading. I am not sure if this is really doable.

I did try to think about that, but its not really doable. Recovery has 1:1 mapping to the grammar, and unless we can rewrite the rule EnumHeaderName ::= Modifiersopt 'enum' Identifier to make it more strict and allow only the valid modifiers, we can't achieve any change in the recovery. That, ofcourse, won't be a very clean way. I have not been able to find any explanation though, as to why EnumHeaderName is chosen over ClassHeaderName. Looks like a random choice to me.

Anyway, with the above patch all tests.
Comment 8 Ayushman Jain CLA 2011-04-13 05:54:00 EDT
Created attachment 193140 [details]
proposed fix + tests

Same patch with tests added.
Comment 9 Olivier Thomann CLA 2011-04-13 10:03:44 EDT
+1
Comment 10 Ayushman Jain CLA 2011-04-13 12:11:58 EDT
Released in HEAD for 3.7M7
Comment 11 Srikanth Sankaran CLA 2011-04-25 04:45:53 EDT
Verified for 3.7 M7 using build I20110421-1800