JDK-6963934 : JCCompilationUnit.getImports does not report all imports
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u20
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2010-06-24
  • Updated: 2012-03-20
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b130Fixed
Description
FULL PRODUCT VERSION :
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux <hostname> 2.6.24-gg804011-generic #1 SMP Tue Mar 30 18:11:30 UTC 2010 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
JCCompilationUnit.getImports does not report all imports if there is an extra semicolon after one of the import statements.

getImports stops after the first non-import statement. Empty statement makes it think there would be no other import statements to follow.



$ cat A.java
import java.util.List;; // note an extra semicolon here
import java.util.ArrayList;

public class A {}

$ cat Driver.java
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.util.JavacTask;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Driver {
  public static void main(String[] args) throws Exception {
    if (args.length < 1) return;

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    JavacTask task = (JavacTask) compiler.getTask(null, fileManager, null, null, null,
                                                  fileManager.getJavaFileObjects(args[0]));
    CompilationUnitTree tree = task.parse().iterator().next();
    for (ImportTree importTree : tree.getImports()) {
      System.out.println(importTree);
    }
  }
}

$ javac A.java accepts the source file as valid

$ javac -cp /java/lib/tools.jar Driver.java
$ java -cp /java/lib/tools.jar:. Driver A.java

produces only the first import statement


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
$ javac -cp /java/lib/tools.jar Driver.java
$ java -cp /java/lib/tools.jar:. Driver A.java

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
import java.util.List;
import java.util.ArrayList;
ACTUAL -
import java.util.List;

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
$ cat A.java
import java.util.List;; // note an extra semicolon here
import java.util.ArrayList;

public class A {}

$ cat Driver.java
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.util.JavacTask;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Driver {
  public static void main(String[] args) throws Exception {
    if (args.length < 1) return;

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    JavacTask task = (JavacTask) compiler.getTask(null, fileManager, null, null, null,
                                                  fileManager.getJavaFileObjects(args[0]));
    CompilationUnitTree tree = task.parse().iterator().next();
    for (ImportTree importTree : tree.getImports()) {
      System.out.println(importTree);
    }
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
My current workaround is to cast CompilationUnitTree to JCTree.JCCompilationUnit and filter the defs myself.

The getImports could be fixed for example by adding if (tree.getTag() == SKIP) continue;

        public List<JCImport> getImports() {
            ListBuffer<JCImport> imports = new ListBuffer<JCImport>();
            for (JCTree tree : defs) {
                if (tree.getTag() == SKIP) continue;
                else if (tree.getTag() == IMPORT)
                    imports.append((JCImport)tree);
                else
                    break;
            }
            return imports.toList();
        }

Comments
EVALUATION verified b124.
2011-01-19