Bug 347396 - ASTParser returns empty or partial AST if we parse when the body contains empty for loop
Summary: ASTParser returns empty or partial AST if we parse when the body contains emp...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: All Windows XP
: P3 normal (vote)
Target Milestone: 3.8 M2   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-05-27 02:30 EDT by Francis Sujai A CLA
Modified: 2011-09-13 04:59 EDT (History)
4 users (show)

See Also:


Attachments
Proposed fix + regression tests (3.96 KB, patch)
2011-09-08 14:36 EDT, Olivier Thomann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Francis Sujai A CLA 2011-05-27 02:30:08 EDT
Build Identifier: Version: 3.6.2, Build id: M20110210-1200

ASTParser parsed with K_STATEMENTS kind and the source contains an empty for loop (e.g. for{};) returns the empty/partial ASTNode.

Tried with parser.setStatementsRecovery(true) also.

I want to parse the code and find analyze it. So, even with errors (syntax/semantic errors in th code), I would like to get the AST with recovered statements and problems. 

I have attached the running test case code and let me know if there is any work around to get the full AST node.

Thanks in advance.

Reproducible: Always

Steps to Reproduce:
Sample code to test this behavior:

if you use the commented out source, AST is returned properly and my visitor could visit all the nodes. 
===================================================

import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;

public class Test {
	public static void main(String args[]){
		ASTParser parser = ASTParser.newParser(AST.JLS3);
		//parser.setSource("int i = 9;  \n int j;\n for(int k = 0; k < i; k++) {int ii =10;}; \n ArrayList<Integer> al = new ArrayList<Integer>();j=1000; ".toCharArray());
		parser.setSource("int i = 9;  \n int j;\n for {}; \n ArrayList<Integer> al = new ArrayList<Integer>();j=1000; ".toCharArray());
		parser.setKind(ASTParser.K_STATEMENTS);
		parser.setStatementsRecovery(true);
 
		final Block block = (Block) parser.createAST(null);
		ASTNode parent = block.getParent();
		while (parent != null && !(parent instanceof CompilationUnit)) {
			parent = parent.getParent();
		}
		final CompilationUnit cu = (CompilationUnit) parent;
		cu.accept(new ASTVisitor() {
 
			Set names = new HashSet();
 
			public boolean visit(VariableDeclarationFragment node) {
				SimpleName name = node.getName();
				this.names.add(name.getIdentifier());
				System.out.println("Declaration of '"+name+"' at line"+cu.getLineNumber(name.getStartPosition()));
				return false; // do not continue to avoid usage info
			}
 
			public boolean visit(SimpleName node) {
				if (this.names.contains(node.getIdentifier())) {
				System.out.println("Usage of '" + node + "' at line " +	cu.getLineNumber(node.getStartPosition()));
				}
				return true;
			}
 
		});
	}
}
Comment 1 Ayushman Jain CLA 2011-05-27 02:46:42 EDT
The AST currently has an EmptyStatement node corresponding to 
for{};

This is completely invalid and not even close to a usual 'for' syntax. What do you expect here?
Comment 2 Francis Sujai A CLA 2011-05-27 02:59:42 EDT
(In reply to comment #1)
> The AST currently has an EmptyStatement node corresponding to 
> for{};
> 
> This is completely invalid and not even close to a usual 'for' syntax. What do
> you expect here?

I understand that. But, is there any way we can recover the other statements.

IMO, statement recovery is meant for that. But, with that also, AST is completely unusable. In case of errors (syntax/semantic), I expect ASTParser to recover all the remaining valid statements and cu.getProblems() will return all the problems(i.e errors).
Comment 3 Olivier Thomann CLA 2011-05-27 08:58:38 EDT
This works fine if the code is wrapped into a compilation unit declaration.
The parser options has to set the compiler source, target and compliance to 1.5 though.
This would require further investigation as why the statement recovery doesn't return the same result with K_STATEMENTS and K_COMPILATION_UNIT.
Comment 4 Olivier Thomann CLA 2011-05-27 09:00:40 EDT
So this works as you expect:
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;

public class Test {
	public static void main(String args[]) {
		ASTParser parser = ASTParser.newParser(AST.JLS3);
		Map options = JavaCore.getOptions();
		options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5);
		options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5);
		options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
				JavaCore.VERSION_1_5);
		parser.setSource("class X { public void foo() { int i = 9;  \n int j;\n for {}; \n ArrayList<Integer> al = new ArrayList<Integer>();j=1000;}}"
				.toCharArray());
		parser.setCompilerOptions(options);
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		parser.setStatementsRecovery(true);

		final CompilationUnit cu = (CompilationUnit) parser.createAST(null);
		cu.accept(new ASTVisitor() {

			Set names = new HashSet();

			public boolean visit(VariableDeclarationFragment node) {
				SimpleName name = node.getName();
				this.names.add(name.getIdentifier());
				System.out.println("Declaration of '" + name + "' at line"
						+ cu.getLineNumber(name.getStartPosition()));
				return false; // do not continue to avoid usage info
			}

			public boolean visit(SimpleName node) {
				if (this.names.contains(node.getIdentifier())) {
					System.out.println("Usage of '" + node + "' at line "
							+ cu.getLineNumber(node.getStartPosition()));
				}
				return true;
			}
		});
	}
}
Comment 5 Olivier Thomann CLA 2011-07-27 15:37:01 EDT
Ayushman, we should investigate why we have a difference between the two kinds: K_STATEMENTS and K_COMPILATION_UNIT. This might hide a more serious issue.
Thanks.
Comment 6 Olivier Thomann CLA 2011-09-02 12:08:23 EDT
I'll see what can be done as Ayushman is in vacations till M2 ships. Might have to be moved to 3.8M3.
Comment 7 Olivier Thomann CLA 2011-09-08 12:37:53 EDT
(In reply to comment #1)
> The AST currently has an EmptyStatement node corresponding to 
> for{};
In fact the recovery produces an empty statement for the ';' part of "for {};". There is no recovered statement at all corresponding to "for {}".

I have a fix which returns the same number of statements using K_STATEMENTS, but it doesn't fix the missing recovered statement for the code "for {}".

Testing the fix right now. Ayushman, we might work on trying to report a recovered statement for the bogus for loop.
Comment 8 Olivier Thomann CLA 2011-09-08 14:36:41 EDT
Created attachment 203017 [details]
Proposed fix + regression tests
Comment 9 Olivier Thomann CLA 2011-09-08 14:36:53 EDT
Released for 3.8M2.
Comment 10 Olivier Thomann CLA 2011-09-08 14:41:38 EDT
(In reply to comment #7)
> Testing the fix right now. Ayushman, we might work on trying to report a
> recovered statement for the bogus for loop.
I opened bug 357139 for this.
Comment 11 Satyam Kandula CLA 2011-09-13 04:59:10 EDT
Verified for 3.8M2 using build I20110912-0800