6877202: Elements.getDocComment() is not getting JavaDocComments
authorjjg
Mon, 27 Sep 2010 14:20:39 -0700
changeset 6716 71df48777dd1
parent 6715 9afc72714ca4
child 6717 0103d76cfe48
6877202: Elements.getDocComment() is not getting JavaDocComments 6861094: javac -Xprint <file> does not print comments 6985205: access to tree positions and doc comments may be lost across annotation processing rounds Reviewed-by: darcy
langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java
langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java
langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java
langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java
langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java
langtools/src/share/classes/com/sun/tools/javac/parser/ScannerFactory.java
langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java
langtools/test/tools/javac/6302184/T6302184.out
langtools/test/tools/javac/6304921/TestLog.java
langtools/test/tools/javac/api/TestJavacTaskScanner.java
langtools/test/tools/javac/processing/Xprint.java
langtools/test/tools/javac/processing/model/util/elements/doccomments/TestDocComments.java
langtools/test/tools/javac/processing/model/util/elements/doccomments/a/First.java
langtools/test/tools/javac/processing/model/util/elements/doccomments/z/Last.java
langtools/test/tools/javac/processing/options/Xprint.java
langtools/test/tools/javac/processing/options/XprintDocComments.java
langtools/test/tools/javac/processing/options/XprintDocComments.out
langtools/test/tools/javac/tree/TreePosRoundsTest.java
--- a/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -99,9 +99,6 @@
     private static Context preRegister(Context context) {
         Bark.preRegister(context);
 
-        // force the use of the scanner that captures Javadoc comments
-        DocCommentScanner.Factory.preRegister(context);
-
         if (context.get(JavaFileManager.class) == null)
             JavacFileManager.preRegister(context);
 
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -96,9 +96,6 @@
         args.getClass();
         context.getClass();
         fileObjects.getClass();
-
-        // force the use of the scanner that captures Javadoc comments
-        com.sun.tools.javac.parser.DocCommentScanner.Factory.preRegister(context);
     }
 
     JavacTaskImpl(JavacTool tool,
@@ -337,9 +334,13 @@
 
             ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>();
             for (JCCompilationUnit unit : units) {
-                for (JCTree node : unit.defs)
-                    if (node.getTag() == JCTree.CLASSDEF)
-                        elements.append(((JCTree.JCClassDecl) node).sym);
+                for (JCTree node : unit.defs) {
+                    if (node.getTag() == JCTree.CLASSDEF) {
+                        JCClassDecl cdef = (JCClassDecl) node;
+                        if (cdef.sym != null) // maybe null if errors in anno processing
+                            elements.append(cdef.sym);
+                    }
+                }
             }
             return elements.toList();
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,9 +62,6 @@
 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
 import static com.sun.tools.javac.util.ListBuffer.lb;
 
-// TEMP, until we have a more efficient way to save doc comment info
-import com.sun.tools.javac.parser.DocCommentScanner;
-
 import java.util.HashMap;
 import java.util.Queue;
 import javax.lang.model.SourceVersion;
@@ -964,11 +961,10 @@
             processAnnotations = procEnvImpl.atLeastOneProcessor();
 
             if (processAnnotations) {
-                if (context.get(Scanner.Factory.scannerFactoryKey) == null)
-                    DocCommentScanner.Factory.preRegister(context);
                 options.put("save-parameter-names", "save-parameter-names");
                 reader.saveParameterNames = true;
                 keepComments = true;
+                genEndPos = true;
                 if (taskListener != null)
                     taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
                 log.deferDiagnostics = true;
@@ -1587,6 +1583,7 @@
     }
 
     public void initRound(JavaCompiler prev) {
+        genEndPos = prev.genEndPos;
         keepComments = prev.keepComments;
         start_msec = prev.start_msec;
         hasBeenUsed = true;
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,50 +42,17 @@
  */
 public class DocCommentScanner extends Scanner {
 
-    /** A factory for creating scanners. */
-    public static class Factory extends Scanner.Factory {
-
-        public static void preRegister(final Context context) {
-            context.put(scannerFactoryKey, new Context.Factory<Scanner.Factory>() {
-                public Factory make() {
-                    return new Factory(context);
-                }
-            });
-        }
-
-        /** Create a new scanner factory. */
-        protected Factory(Context context) {
-            super(context);
-        }
-
-        @Override
-        public Scanner newScanner(CharSequence input) {
-            if (input instanceof CharBuffer) {
-                return new DocCommentScanner(this, (CharBuffer)input);
-            } else {
-                char[] array = input.toString().toCharArray();
-                return newScanner(array, array.length);
-            }
-        }
-
-        @Override
-        public Scanner newScanner(char[] input, int inputLength) {
-            return new DocCommentScanner(this, input, inputLength);
-        }
-    }
-
-
     /** Create a scanner from the input buffer.  buffer must implement
      *  array() and compact(), and remaining() must be less than limit().
      */
-    protected DocCommentScanner(Factory fac, CharBuffer buffer) {
+    protected DocCommentScanner(ScannerFactory fac, CharBuffer buffer) {
         super(fac, buffer);
     }
 
     /** Create a scanner from the input array.  The array must have at
      *  least a single character of extra space.
      */
-    protected DocCommentScanner(Factory fac, char[] input, int inputLength) {
+    protected DocCommentScanner(ScannerFactory fac, char[] input, int inputLength) {
         super(fac, input, inputLength);
     }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -2473,6 +2473,11 @@
                 defs.append(importDeclaration());
             } else {
                 JCTree def = typeDeclaration(mods);
+                if (keepDocComments && dc != null && docComments.get(def) == dc) {
+                    // If the first type declaration has consumed the first doc
+                    // comment, then don't use it for the top level comment as well.
+                    dc = null;
+                }
                 if (def instanceof JCExpressionStatement)
                     def = ((JCExpressionStatement)def).expr;
                 defs.append(def);
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,7 @@
     final Source source;
     final Names names;
     final Options options;
-    final Scanner.Factory scannerFactory;
+    final ScannerFactory scannerFactory;
 
     protected ParserFactory(Context context) {
         super();
@@ -70,11 +70,11 @@
         this.keywords = Keywords.instance(context);
         this.source = Source.instance(context);
         this.options = Options.instance(context);
-        this.scannerFactory = Scanner.Factory.instance(context);
+        this.scannerFactory = ScannerFactory.instance(context);
     }
 
     public Parser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) {
-        Lexer lexer = scannerFactory.newScanner(input);
+        Lexer lexer = scannerFactory.newScanner(input, keepDocComments);
         if (keepEndPos) {
             return new EndPosParser(this, lexer, keepDocComments, keepLineMap);
         } else {
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,48 +47,6 @@
 
     private static boolean scannerDebug = false;
 
-    /** A factory for creating scanners. */
-    public static class Factory {
-        /** The context key for the scanner factory. */
-        public static final Context.Key<Scanner.Factory> scannerFactoryKey =
-            new Context.Key<Scanner.Factory>();
-
-        /** Get the Factory instance for this context. */
-        public static Factory instance(Context context) {
-            Factory instance = context.get(scannerFactoryKey);
-            if (instance == null)
-                instance = new Factory(context);
-            return instance;
-        }
-
-        final Log log;
-        final Names names;
-        final Source source;
-        final Keywords keywords;
-
-        /** Create a new scanner factory. */
-        protected Factory(Context context) {
-            context.put(scannerFactoryKey, this);
-            this.log = Log.instance(context);
-            this.names = Names.instance(context);
-            this.source = Source.instance(context);
-            this.keywords = Keywords.instance(context);
-        }
-
-        public Scanner newScanner(CharSequence input) {
-            if (input instanceof CharBuffer) {
-                return new Scanner(this, (CharBuffer)input);
-            } else {
-                char[] array = input.toString().toCharArray();
-                return newScanner(array, array.length);
-            }
-        }
-
-        public Scanner newScanner(char[] input, int inputLength) {
-            return new Scanner(this, input, inputLength);
-        }
-    }
-
     /* Output variables; set by nextToken():
      */
 
@@ -177,7 +135,7 @@
     private final Keywords keywords;
 
     /** Common code for constructors. */
-    private Scanner(Factory fac) {
+    private Scanner(ScannerFactory fac) {
         log = fac.log;
         names = fac.names;
         keywords = fac.keywords;
@@ -201,7 +159,7 @@
     /** Create a scanner from the input buffer.  buffer must implement
      *  array() and compact(), and remaining() must be less than limit().
      */
-    protected Scanner(Factory fac, CharBuffer buffer) {
+    protected Scanner(ScannerFactory fac, CharBuffer buffer) {
         this(fac, JavacFileManager.toArray(buffer), buffer.limit());
     }
 
@@ -216,7 +174,7 @@
      * @param inputLength the size of the input.
      * Must be positive and less than or equal to input.length.
      */
-    protected Scanner(Factory fac, char[] input, int inputLength) {
+    protected Scanner(ScannerFactory fac, char[] input, int inputLength) {
         this(fac);
         eofPos = inputLength;
         if (inputLength == input.length) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/ScannerFactory.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.parser;
+
+import java.nio.CharBuffer;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+
+
+/**
+ * A factory for creating scanners.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own
+ *  risk.  This code and its internal interfaces are subject to change
+ *  or deletion without notice.</b>
+ */
+public class ScannerFactory {
+    /** The context key for the scanner factory. */
+    public static final Context.Key<ScannerFactory> scannerFactoryKey =
+        new Context.Key<ScannerFactory>();
+
+    /** Get the Factory instance for this context. */
+    public static ScannerFactory instance(Context context) {
+        ScannerFactory instance = context.get(scannerFactoryKey);
+        if (instance == null)
+            instance = new ScannerFactory(context);
+        return instance;
+    }
+
+    final Log log;
+    final Names names;
+    final Source source;
+    final Keywords keywords;
+
+    /** Create a new scanner factory. */
+    protected ScannerFactory(Context context) {
+        context.put(scannerFactoryKey, this);
+        this.log = Log.instance(context);
+        this.names = Names.instance(context);
+        this.source = Source.instance(context);
+        this.keywords = Keywords.instance(context);
+    }
+
+    public Scanner newScanner(CharSequence input, boolean keepDocComments) {
+        if (input instanceof CharBuffer) {
+            CharBuffer buf = (CharBuffer) input;
+            if (keepDocComments)
+                return new DocCommentScanner(this, buf);
+            else
+                return new Scanner(this, buf);
+        } else {
+            char[] array = input.toString().toCharArray();
+            return newScanner(array, array.length, keepDocComments);
+        }
+    }
+
+    public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) {
+        if (keepDocComments)
+            return new DocCommentScanner(this, input, inputLength);
+        else
+            return new Scanner(this, input, inputLength);
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -107,9 +107,6 @@
             // force the use of Messager as a Log
             messager = Messager.instance0(context);
 
-            // force the use of the scanner that captures Javadoc comments
-            DocCommentScanner.Factory.preRegister(context);
-
             return new JavadocTool(context);
         } catch (CompletionFailure ex) {
             messager.error(Position.NOPOS, ex.getMessage());
--- a/langtools/test/tools/javac/6302184/T6302184.out	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/test/tools/javac/6302184/T6302184.out	Mon Sep 27 14:20:39 2010 -0700
@@ -1,4 +1,7 @@
 
+/**
+ * This is a test that uses ISO 8859 encoding.
+ */
 class T6302184 {
     
     T6302184() {
--- a/langtools/test/tools/javac/6304921/TestLog.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/test/tools/javac/6304921/TestLog.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@
 import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.parser.Parser;
 import com.sun.tools.javac.parser.ParserFactory;
-import com.sun.tools.javac.parser.Scanner;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.TreeScanner;
 import com.sun.tools.javac.util.Context;
@@ -60,7 +59,6 @@
         log.multipleErrors = true;
 
         JavacFileManager.preRegister(context);
-        Scanner.Factory sfac = Scanner.Factory.instance(context);
         ParserFactory pfac = ParserFactory.instance(context);
 
         final String text =
--- a/langtools/test/tools/javac/api/TestJavacTaskScanner.java	Mon Sep 27 14:05:33 2010 -0700
+++ b/langtools/test/tools/javac/api/TestJavacTaskScanner.java	Mon Sep 27 14:20:39 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,8 +31,8 @@
  */
 
 import com.sun.tools.javac.api.JavacTaskImpl;
-import com.sun.tools.javac.parser.*; // XXX
-import com.sun.tools.javac.util.*; // XXX
+import com.sun.tools.javac.parser.*;
+import com.sun.tools.javac.util.*;
 import java.io.*;
 import java.net.*;
 import java.nio.*;
@@ -65,7 +65,7 @@
             fm.getJavaFileObjects(new File[] {file});
         StandardJavaFileManager fm = getLocalFileManager(tool, null, null);
         task = (JavacTaskImpl)tool.getTask(null, fm, null, null, null, compilationUnits);
-        task.getContext().put(Scanner.Factory.scannerFactoryKey,
+        task.getContext().put(ScannerFactory.scannerFactoryKey,
                 new MyScanner.Factory(task.getContext(), this));
         elements = task.getElements();
         types = task.getTypes();
@@ -170,34 +170,36 @@
 
 class MyScanner extends Scanner {
 
-    public static class Factory extends Scanner.Factory {
+    public static class Factory extends ScannerFactory {
         public Factory(Context context, TestJavacTaskScanner test) {
             super(context);
             this.test = test;
         }
 
         @Override
-        public Scanner newScanner(CharSequence input) {
+        public Scanner newScanner(CharSequence input, boolean keepDocComments) {
+            assert !keepDocComments;
             if (input instanceof CharBuffer) {
                 return new MyScanner(this, (CharBuffer)input, test);
             } else {
                 char[] array = input.toString().toCharArray();
-                return newScanner(array, array.length);
+                return newScanner(array, array.length, keepDocComments);
             }
         }
 
         @Override
-        public Scanner newScanner(char[] input, int inputLength) {
+        public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) {
+            assert !keepDocComments;
             return new MyScanner(this, input, inputLength, test);
         }
 
         private TestJavacTaskScanner test;
     }
-    protected MyScanner(Factory fac, CharBuffer buffer, TestJavacTaskScanner test) {
+    protected MyScanner(ScannerFactory fac, CharBuffer buffer, TestJavacTaskScanner test) {
         super(fac, buffer);
         this.test = test;
     }
-    protected MyScanner(Factory fac, char[] input, int inputLength, TestJavacTaskScanner test) {
+    protected MyScanner(ScannerFactory fac, char[] input, int inputLength, TestJavacTaskScanner test) {
         super(fac, input, inputLength);
         this.test = test;
     }
--- a/langtools/test/tools/javac/processing/Xprint.java	Mon Sep 27 14:05:33 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug     6266828
- * @summary JSR 269: Java Language Model API
- * @author  Peter von der Ah\u00e9
- */
-import javax.tools.JavaCompiler;
-import javax.tools.ToolProvider;
-
-public class Xprint {
-    public static void main(String[] args) {
-        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
-        javac.run(System.in, null, null,
-                  "-Xprint",
-                  "com.sun.tools.javac.code.Types",
-                  "com.sun.tools.javac.parser.Parser",
-                  "java.util.EnumSet");
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/util/elements/doccomments/TestDocComments.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6877202
+ * @summary Elements.getDocComment() is not getting JavaDocComments
+ */
+
+import com.sun.source.tree.*;
+import com.sun.source.util.*;
+import java.io.*;
+import java.util.*;
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import javax.tools.*;
+
+/*
+ * For a mixture of pre-existing and generated source files, ensure that we can
+ * get the doc comments.
+ * The test uses both a standard ElementScanner to find all the elements being
+ * processed, and a TreeScanner to find all the local and anonymous inner classes
+ * as well.
+ * And, because the relevant code paths in the compiler are different for
+ * command line and JSR 199 invocation, the test covers both ways of invoking the
+ * compiler.
+ */
+
+@SupportedOptions("scan")
+@SupportedAnnotationTypes("*")
+public class TestDocComments extends AbstractProcessor {
+    enum CompileKind { API, CMD };
+    enum ScanKind { TREE, ELEMENT };
+
+    // ----- Main test driver: invoke compiler for the various test cases ------
+
+    public static void main(String... args) throws Exception {
+        for (CompileKind ck: CompileKind.values()) {
+            for (ScanKind sk: ScanKind.values()) {
+                try {
+                    test(ck, sk);
+                } catch (IOException e) {
+                    error(e.toString());
+                }
+            }
+        }
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    static void test(CompileKind ck, ScanKind sk) throws IOException {
+        String testClasses = System.getProperty("test.classes");
+        String testSrc = System.getProperty("test.src");
+        File testDir = new File("test." + ck + "." + sk);
+        testDir.mkdirs();
+        String[] opts = {
+            "-d", testDir.getPath(),
+            "-implicit:none",
+            "-processor", TestDocComments.class.getName(),
+            "-processorpath", testClasses,
+            //"-XprintRounds",
+            "-Ascan=" + sk
+        };
+        File[] files = {
+            new File(testSrc, "a/First.java")
+        };
+
+        if (ck == CompileKind.API)
+            test_javac_api(opts, files);
+        else
+            test_javac_cmd(opts, files);
+    }
+
+    static void test_javac_api(String[] opts, File[] files) throws IOException {
+        System.err.println("test javac api: " + Arrays.asList(opts) + " " + Arrays.asList(files));
+        DiagnosticListener<JavaFileObject> dl = new DiagnosticListener<JavaFileObject>() {
+            public void report(Diagnostic diagnostic) {
+                error(diagnostic.toString());
+            }
+        };
+        JavaCompiler c = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
+        Iterable<? extends JavaFileObject> units = fm.getJavaFileObjects(files);
+        JavacTask t = (JavacTask) c.getTask(null, fm, dl, Arrays.asList(opts), null, units);
+        t.parse();
+        t.analyze();
+    }
+
+    static void test_javac_cmd(String[] opts, File[] files) {
+        System.err.println("test javac cmd: " + Arrays.asList(opts) + " " + Arrays.asList(files));
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        List<String> args = new ArrayList<String>(Arrays.asList(opts));
+        for (File f: files)
+            args.add(f.getPath());
+        int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
+        pw.close();
+        String out = sw.toString();
+        if (out.length() > 0)
+            System.err.println(out);
+        if (rc > 0)
+            error("Compilation failed: rc=" + rc);
+    }
+
+    static void error(String msg) {
+        System.err.println(msg);
+        errors++;
+        //throw new Error(msg);
+    }
+
+    static int errors;
+
+    // ----- Annotation processor: scan for elements and check doc comments ----
+
+    Map<String,String> options;
+    Filer filer;
+    Messager messager;
+    Elements elements;
+    ScanKind skind;
+
+    int round = 0;
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
+    public void init(ProcessingEnvironment pEnv) {
+        super.init(pEnv);
+        options = pEnv.getOptions();
+        filer = pEnv.getFiler();
+        messager = pEnv.getMessager();
+        elements = pEnv.getElementUtils();
+        skind = ScanKind.valueOf(options.get("scan"));
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        round++;
+
+        // Scan elements using an appropriate scanner, and for each element found,
+        // call check(Element e) to verify the doc comment on that element
+        for (Element e: roundEnv.getRootElements()) {
+            System.err.println("scan " + skind + " " + e.getKind() + " " + e.getSimpleName());
+            if (skind == ScanKind.TREE) {
+                Trees trees = Trees.instance(processingEnv); // cannot cache this across rounds
+                new TestTreeScanner().scan(trees.getPath(e), trees);
+            }  else
+                new TestElementScanner().scan(e);
+        }
+
+        // For a few rounds, generate new source files, so that we can check whether
+        // doc comments are correctly handled in subsequent processing rounds
+        final int MAX_ROUNDS = 3;
+        if (round <= MAX_ROUNDS) {
+            String pkg = "p";
+            String currClass = "Gen" + round;
+            String curr = pkg + "." + currClass;
+            String next = (round < MAX_ROUNDS) ? (pkg + ".Gen" + (round + 1)) : "z.Last";
+            StringBuilder text = new StringBuilder();
+            text.append("package ").append(pkg).append(";\n");
+            text.append("/** CLASS ").append(currClass).append(" */\n");
+            text.append("public class ").append(currClass).append(" {\n");
+            text.append("    /** CONSTRUCTOR <init> **/\n");
+            text.append("    ").append(currClass).append("() { }\n");
+            text.append("    /** FIELD x */\n");
+            text.append("    ").append(next).append(" x;\n");
+            text.append("    /** METHOD m */\n");
+            text.append("    void m() { }\n");
+            text.append("}\n");
+
+            try {
+                JavaFileObject fo = filer.createSourceFile(curr);
+                Writer out = fo.openWriter();
+                try {
+                    out.write(text.toString());
+                } finally {
+                    out.close();
+                }
+            } catch (IOException e) {
+                throw new Error(e);
+            }
+        }
+
+        return true;
+    }
+
+    /*
+     * Check that the doc comment on an element is as expected.
+     * This method is invoked for each element found by the scanners run by process.
+     */
+    void check(Element e) {
+        System.err.println("Checking " + e);
+
+        String dc = elements.getDocComment(e);
+        System.err.println("   found " + dc);
+
+        String expect = (e.getKind() + " " + e.getSimpleName()); // default
+
+        Name name = e.getSimpleName();
+        Element encl = e.getEnclosingElement();
+        Name enclName = encl.getSimpleName();
+        ElementKind enclKind = encl.getKind();
+        switch (e.getKind()) {
+            case PARAMETER:
+            case LOCAL_VARIABLE:
+                // doc comments not retained for these elements
+                expect = null;
+                break;
+
+            case CONSTRUCTOR:
+                if (enclName.length() == 0 || enclKind == ElementKind.ENUM) {
+                    // Enum constructor is synthetic
+                    expect = null;
+                }
+                break;
+
+            case METHOD:
+                if (enclKind == ElementKind.ENUM
+                        && (name.contentEquals("values") || name.contentEquals("valueOf"))) {
+                    // synthetic enum methods
+                    expect = null;
+                }
+                break;
+
+            case CLASS:
+                if (e.getSimpleName().length() == 0) {
+                    // anon inner class
+                    expect = null;
+                }
+                break;
+        }
+
+        System.err.println("  expect " + expect);
+
+        if (dc == null ? expect == null : dc.trim().equals(expect))
+            return;
+
+        if (dc == null)
+            messager.printMessage(Diagnostic.Kind.ERROR, "doc comment is null", e);
+        else {
+            messager.printMessage(Diagnostic.Kind.ERROR,
+                    "unexpected comment: \"" + dc + "\", expected \"" + expect + "\"", e);
+        }
+    }
+
+    // ----- Scanners to find elements -----------------------------------------
+
+    class TestElementScanner extends ElementScanner7<Void, Void> {
+        @Override
+        public Void visitExecutable(ExecutableElement e, Void _) {
+            check(e);
+            return super.visitExecutable(e, _);
+        }
+        @Override
+        public Void visitType(TypeElement e, Void _) {
+            check(e);
+            return super.visitType(e, _);
+        }
+        @Override
+        public Void visitVariable(VariableElement e, Void _) {
+            check(e);
+            return super.visitVariable(e, _);
+        }
+    }
+
+    class TestTreeScanner extends TreePathScanner<Void,Trees> {
+        @Override
+        public Void visitClass(ClassTree tree, Trees trees) {
+            check(trees.getElement(getCurrentPath()));
+            return super.visitClass(tree, trees);
+        }
+        @Override
+        public Void visitMethod(MethodTree tree, Trees trees) {
+            check(trees.getElement(getCurrentPath()));
+            return super.visitMethod(tree, trees);
+        }
+        @Override
+        public Void visitVariable(VariableTree tree, Trees trees) {
+            check(trees.getElement(getCurrentPath()));
+            return super.visitVariable(tree, trees);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/util/elements/doccomments/a/First.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package a;
+
+/** CLASS First */
+public class First {
+    /** CONSTRUCTOR <init> */
+    First() { }
+
+    /** FIELD x */
+    p.Gen1 x;
+
+    /** METHOD m **/
+    void m(int i) {
+        /** CLASS Local */
+        class Local {
+            /** CONSTRUCTOR <init> */
+            Local() { }
+        }
+
+        Runnable r = new Runnable() {
+            /** METHOD run **/
+            public void run() { }
+        };
+
+    }
+
+    /** ENUM E */
+    enum E {
+        /** ENUM_CONSTANT e1 */
+        e1
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/util/elements/doccomments/z/Last.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package z;
+
+// This class should be read last, implicitly. Therefore it should not
+// be subject to anno processing. If it is, the lack of doc comments should
+// be detected and will flag an error.
+public class Last {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/options/Xprint.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug     6266828
+ * @summary JSR 269: Java Language Model API
+ * @author  Peter von der Ah\u00e9
+ */
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+
+public class Xprint {
+    public static void main(String[] args) {
+        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
+        javac.run(System.in, null, null,
+                  "-Xprint",
+                  "com.sun.tools.javac.code.Types",
+                  "com.sun.tools.javac.parser.Parser",
+                  "java.util.EnumSet");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/options/XprintDocComments.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6861094
+ * @summary javac -Xprint <file> does not print comments
+ * @compile/ref=XprintDocComments.out -Xprint  XprintDocComments.java
+ */
+
+/**
+ * CLASS XprintDocComments
+ */
+class XPrintDocComments {
+    /**
+     * FIELD i;
+     */
+    int i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/options/XprintDocComments.out	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,12 @@
+
+/**
+ * CLASS XprintDocComments
+ */
+class XPrintDocComments {
+
+  XPrintDocComments();
+  /**
+   * FIELD i;
+   */
+  int i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/tree/TreePosRoundsTest.java	Mon Sep 27 14:20:39 2010 -0700
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6985205
+ * @summary access to tree positions and doc comments may be lost across annotation processing rounds
+ * @build TreePosRoundsTest
+ * @compile -proc:only -processor TreePosRoundsTest TreePosRoundsTest.java
+ * @run main TreePosRoundsTest
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.tools.*;
+
+import com.sun.source.tree.*;
+import com.sun.source.util.*;
+import javax.tools.JavaCompiler.CompilationTask;
+
+// This test is an annotation processor that performs multiple rounds of
+// processing, and on each round, it checks that source positions are
+// available and correct.
+//
+// The test can be run directly as a processor from the javac command line
+// or via JSR 199 by invoking the main program.
+
+@SupportedAnnotationTypes("*")
+public class TreePosRoundsTest extends AbstractProcessor {
+    public static void main(String... args) throws Exception {
+        String testSrc = System.getProperty("test.src");
+        String testClasses = System.getProperty("test.classes");
+        JavaCompiler c = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
+        String thisName = TreePosRoundsTest.class.getName();
+        File thisFile = new File(testSrc, thisName + ".java");
+        Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(thisFile);
+        List<String> options = Arrays.asList(
+                "-proc:only",
+                "-processor", thisName,
+                "-processorpath", testClasses);
+        CompilationTask t = c.getTask(null, fm, null, options, null, files);
+        boolean ok = t.call();
+        if (!ok)
+            throw new Exception("processing failed");
+    }
+
+    Filer filer;
+    Messager messager;
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
+    public void init(ProcessingEnvironment pEnv) {
+        super.init(pEnv);
+        filer = pEnv.getFiler();
+        messager = pEnv.getMessager();
+    }
+
+    int round = 0;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        round++;
+
+        // Scan trees for elements, verifying source tree positions
+        for (Element e: roundEnv.getRootElements()) {
+            try {
+                Trees trees = Trees.instance(processingEnv); // cannot cache this across rounds
+                TreePath p = trees.getPath(e);
+                new TestTreeScanner(p.getCompilationUnit(), trees).scan(trees.getPath(e), null);
+            } catch (IOException ex) {
+                messager.printMessage(Diagnostic.Kind.ERROR,
+                        "Cannot get source: " + ex, e);
+            }
+        }
+
+        final int MAXROUNDS = 3;
+        if (round < MAXROUNDS)
+            generateSource("Gen" + round);
+
+        return true;
+    }
+
+    void generateSource(String name) {
+        StringBuilder text = new StringBuilder();
+        text.append("class ").append(name).append("{\n");
+        text.append("    int one = 1;\n");
+        text.append("    int two = 2;\n");
+        text.append("    int three = one + two;\n");
+        text.append("}\n");
+
+        try {
+            JavaFileObject fo = filer.createSourceFile(name);
+            Writer out = fo.openWriter();
+            try {
+                out.write(text.toString());
+            } finally {
+                out.close();
+            }
+        } catch (IOException e) {
+            throw new Error(e);
+        }
+    }
+
+    class TestTreeScanner extends TreePathScanner<Void,Void> {
+        TestTreeScanner(CompilationUnitTree unit, Trees trees) throws IOException {
+            this.unit = unit;
+            JavaFileObject sf = unit.getSourceFile();
+            source = sf.getCharContent(true).toString();
+            sourcePositions = trees.getSourcePositions();
+        }
+
+        @Override
+        public Void visitVariable(VariableTree tree, Void _) {
+            check(getCurrentPath());
+            return super.visitVariable(tree, _);
+        }
+
+        void check(TreePath tp) {
+            Tree tree = tp.getLeaf();
+
+            String expect = tree.toString();
+            if (tree.getKind() == Tree.Kind.VARIABLE) {
+                // tree.toString() does not know enough context to add ";",
+                // so deal with that manually...
+                Tree.Kind enclKind = tp.getParentPath().getLeaf().getKind();
+                //System.err.println("  encl: " +enclKind);
+                if (enclKind == Tree.Kind.CLASS || enclKind == Tree.Kind.BLOCK)
+                    expect += ";";
+            }
+            //System.err.println("expect: " + expect);
+
+            int start = (int)sourcePositions.getStartPosition(unit, tree);
+            if (start == Diagnostic.NOPOS) {
+                messager.printMessage(Diagnostic.Kind.ERROR, "start pos not set for " + trim(tree));
+                return;
+            }
+
+            int end = (int)sourcePositions.getEndPosition(unit, tree);
+            if (end == Diagnostic.NOPOS) {
+                messager.printMessage(Diagnostic.Kind.ERROR, "end pos not set for " + trim(tree));
+                return;
+            }
+
+            String found = source.substring(start, end);
+            //System.err.println(" found: " + found);
+
+            // allow for long lines, in which case just compare beginning and
+            // end of the strings
+            boolean equal;
+            if (found.contains("\n")) {
+                String head = found.substring(0, found.indexOf("\n"));
+                String tail = found.substring(found.lastIndexOf("\n")).trim();
+                equal = expect.startsWith(head) && expect.endsWith(tail);
+            } else {
+                equal = expect.equals(found);
+            }
+
+            if (!equal) {
+                messager.printMessage(Diagnostic.Kind.ERROR,
+                        "unexpected value found: '" + found + "'; expected: '" + expect + "'");
+            }
+        }
+
+        String trim(Tree tree) {
+            final int MAXLEN = 32;
+            String s = tree.toString().replaceAll("\\s+", " ").trim();
+            return (s.length() < MAXLEN) ? s : s.substring(0, MAXLEN);
+
+        }
+
+        CompilationUnitTree unit;
+        SourcePositions sourcePositions;
+        String source;
+    }
+
+}