6970584: Flow.java should be more error-friendly

Tue, 07 Sep 2010 17:33:43 +0100

author
mcimadamore
date
Tue, 07 Sep 2010 17:33:43 +0100
changeset 676
bfdfc13fe641
parent 675
12d8f7e417fd
child 677
c388fa8c6a43

6970584: Flow.java should be more error-friendly
Summary: Added a post-attribution visitor that fixup uninitialized types/symbol in AST after erroneous attribution
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/code/Symtab.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Annotate.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Flow.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/main/JavaCompiler.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/CheckAttributedTree.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver01.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver01.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver02.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver02.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver03.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver03.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver04.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver04.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver05.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver05.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver06.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver06.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver07.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver07.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver08.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver08.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver09.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver09.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver10.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver10.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver11.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver11.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver12.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver12.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver13.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver13.out file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver14.java file | annotate | diff | comparison | revisions
test/tools/javac/failover/FailOver14.out file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Sep 07 17:32:52 2010 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Sep 07 17:33:43 2010 +0100
     1.3 @@ -93,6 +93,10 @@
     1.4       */
     1.5      public final ClassSymbol errSymbol;
     1.6  
     1.7 +    /** The unknown symbol.
     1.8 +     */
     1.9 +    public final ClassSymbol unknownSymbol;
    1.10 +
    1.11      /** A value for the errType, with a originalType of noType */
    1.12      public final Type errType;
    1.13  
    1.14 @@ -354,6 +358,7 @@
    1.15  
    1.16          // create the error symbols
    1.17          errSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.any, null, rootPackage);
    1.18 +        unknownSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.fromString("<any?>"), null, rootPackage);
    1.19          errType = new ErrorType(errSymbol, Type.noType);
    1.20  
    1.21          // initialize builtin types
    1.22 @@ -368,7 +373,7 @@
    1.23          initType(voidType, "void", "Void");
    1.24          initType(botType, "<nulltype>");
    1.25          initType(errType, errSymbol);
    1.26 -        initType(unknownType, "<any?>");
    1.27 +        initType(unknownType, unknownSymbol);
    1.28  
    1.29          // the builtin class of all arrays
    1.30          arrayClass = new ClassSymbol(PUBLIC|ACYCLIC, names.Array, noSymbol);
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Sep 07 17:32:52 2010 +0100
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Sep 07 17:33:43 2010 +0100
     2.3 @@ -182,6 +182,7 @@
     2.4              if (!method.type.isErroneous())
     2.5                  buf.append(new Pair<MethodSymbol,Attribute>
     2.6                             ((MethodSymbol)method, value));
     2.7 +            t.type = result;
     2.8          }
     2.9          return new Attribute.Compound(a.type, buf.toList());
    2.10      }
    2.11 @@ -234,6 +235,7 @@
    2.12                                                 l.head,
    2.13                                                 env));
    2.14              }
    2.15 +            na.type = expected;
    2.16              return new Attribute.
    2.17                  Array(expected, buf.toArray(new Attribute[buf.length()]));
    2.18          }
     3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 07 17:32:52 2010 +0100
     3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 07 17:33:43 2010 +0100
     3.3 @@ -3201,4 +3201,104 @@
     3.4              super.visitMethodDef(tree);
     3.5          }
     3.6      };
     3.7 +
     3.8 +    // <editor-fold desc="post-attribution visitor">
     3.9 +
    3.10 +    /**
    3.11 +     * Handle missing types/symbols in an AST. This routine is useful when
    3.12 +     * the compiler has encountered some errors (which might have ended up
    3.13 +     * terminating attribution abruptly); if the compiler is used in fail-over
    3.14 +     * mode (e.g. by an IDE) and the AST contains semantic errors, this routine
    3.15 +     * prevents NPE to be progagated during subsequent compilation steps.
    3.16 +     */
    3.17 +    public void postAttr(Env<AttrContext> env) {
    3.18 +        new PostAttrAnalyzer().scan(env.tree);
    3.19 +    }
    3.20 +
    3.21 +    class PostAttrAnalyzer extends TreeScanner {
    3.22 +
    3.23 +        private void initTypeIfNeeded(JCTree that) {
    3.24 +            if (that.type == null) {
    3.25 +                that.type = syms.unknownType;
    3.26 +            }
    3.27 +        }
    3.28 +
    3.29 +        @Override
    3.30 +        public void scan(JCTree tree) {
    3.31 +            if (tree == null) return;
    3.32 +            if (tree instanceof JCExpression) {
    3.33 +                initTypeIfNeeded(tree);
    3.34 +            }
    3.35 +            super.scan(tree);
    3.36 +        }
    3.37 +
    3.38 +        @Override
    3.39 +        public void visitIdent(JCIdent that) {
    3.40 +            if (that.sym == null) {
    3.41 +                that.sym = syms.unknownSymbol;
    3.42 +            }
    3.43 +        }
    3.44 +
    3.45 +        @Override
    3.46 +        public void visitSelect(JCFieldAccess that) {
    3.47 +            if (that.sym == null) {
    3.48 +                that.sym = syms.unknownSymbol;
    3.49 +            }
    3.50 +            super.visitSelect(that);
    3.51 +        }
    3.52 +
    3.53 +        @Override
    3.54 +        public void visitClassDef(JCClassDecl that) {
    3.55 +            initTypeIfNeeded(that);
    3.56 +            if (that.sym == null) {
    3.57 +                that.sym = new ClassSymbol(0, that.name, that.type, syms.noSymbol);
    3.58 +            }
    3.59 +            super.visitClassDef(that);
    3.60 +        }
    3.61 +
    3.62 +        @Override
    3.63 +        public void visitMethodDef(JCMethodDecl that) {
    3.64 +            initTypeIfNeeded(that);
    3.65 +            if (that.sym == null) {
    3.66 +                that.sym = new MethodSymbol(0, that.name, that.type, syms.noSymbol);
    3.67 +            }
    3.68 +            super.visitMethodDef(that);
    3.69 +        }
    3.70 +
    3.71 +        @Override
    3.72 +        public void visitVarDef(JCVariableDecl that) {
    3.73 +            initTypeIfNeeded(that);
    3.74 +            if (that.sym == null) {
    3.75 +                that.sym = new VarSymbol(0, that.name, that.type, syms.noSymbol);
    3.76 +                that.sym.adr = 0;
    3.77 +            }
    3.78 +            super.visitVarDef(that);
    3.79 +        }
    3.80 +
    3.81 +        @Override
    3.82 +        public void visitNewClass(JCNewClass that) {
    3.83 +            if (that.constructor == null) {
    3.84 +                that.constructor = new MethodSymbol(0, names.init, syms.unknownType, syms.noSymbol);
    3.85 +            }
    3.86 +            if (that.constructorType == null) {
    3.87 +                that.constructorType = syms.unknownType;
    3.88 +            }
    3.89 +            super.visitNewClass(that);
    3.90 +        }
    3.91 +
    3.92 +        @Override
    3.93 +        public void visitBinary(JCBinary that) {
    3.94 +            if (that.operator == null)
    3.95 +                that.operator = new OperatorSymbol(names.empty, syms.unknownType, -1, syms.noSymbol);
    3.96 +            super.visitBinary(that);
    3.97 +        }
    3.98 +
    3.99 +        @Override
   3.100 +        public void visitUnary(JCUnary that) {
   3.101 +            if (that.operator == null)
   3.102 +                that.operator = new OperatorSymbol(names.empty, syms.unknownType, -1, syms.noSymbol);
   3.103 +            super.visitUnary(that);
   3.104 +        }
   3.105 +    }
   3.106 +    // </editor-fold>
   3.107  }
     4.1 --- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Sep 07 17:32:52 2010 +0100
     4.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Sep 07 17:33:43 2010 +0100
     4.3 @@ -408,7 +408,9 @@
     4.4          tree = TreeInfo.skipParens(tree);
     4.5          if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
     4.6              Symbol sym = TreeInfo.symbol(tree);
     4.7 -            letInit(tree.pos(), (VarSymbol)sym);
     4.8 +            if (sym.kind == VAR) {
     4.9 +                letInit(tree.pos(), (VarSymbol)sym);
    4.10 +            }
    4.11          }
    4.12      }
    4.13  
    4.14 @@ -481,12 +483,13 @@
    4.15  
    4.16      /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
    4.17       */
    4.18 -    void split() {
    4.19 +    void split(boolean setToNull) {
    4.20          initsWhenFalse = inits.dup();
    4.21          uninitsWhenFalse = uninits.dup();
    4.22          initsWhenTrue = inits;
    4.23          uninitsWhenTrue = uninits;
    4.24 -        inits = uninits = null;
    4.25 +        if (setToNull)
    4.26 +            inits = uninits = null;
    4.27      }
    4.28  
    4.29      /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
    4.30 @@ -568,9 +571,11 @@
    4.31              uninitsWhenTrue = uninits;
    4.32          } else {
    4.33              scan(tree);
    4.34 -            if (inits != null) split();
    4.35 +            if (inits != null)
    4.36 +                split(tree.type != syms.unknownType);
    4.37          }
    4.38 -        inits = uninits = null;
    4.39 +        if (tree.type != syms.unknownType)
    4.40 +            inits = uninits = null;
    4.41      }
    4.42  
    4.43      /* ------------ Visitor methods for various sorts of trees -------------*/
    4.44 @@ -1007,7 +1012,7 @@
    4.45                  List.of(resource.type);
    4.46              for (Type sup : closeableSupertypes) {
    4.47                  if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
    4.48 -                    Symbol closeMethod = rs.resolveInternalMethod(tree,
    4.49 +                    Symbol closeMethod = rs.resolveQualifiedMethod(tree,
    4.50                              attrEnv,
    4.51                              sup,
    4.52                              names.close,
    4.53 @@ -1050,20 +1055,22 @@
    4.54              List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
    4.55              for (JCExpression ct : subClauses) {
    4.56                  Type exc = ct.type;
    4.57 -                ctypes = ctypes.append(exc);
    4.58 -                if (types.isSameType(exc, syms.objectType))
    4.59 -                    continue;
    4.60 -                if (chk.subset(exc, caughtInTry)) {
    4.61 -                    log.error(l.head.pos(),
    4.62 -                              "except.already.caught", exc);
    4.63 -                } else if (!chk.isUnchecked(l.head.pos(), exc) &&
    4.64 -                           exc.tsym != syms.throwableType.tsym &&
    4.65 -                           exc.tsym != syms.exceptionType.tsym &&
    4.66 -                           !chk.intersects(exc, thrownInTry)) {
    4.67 -                    log.error(l.head.pos(),
    4.68 -                              "except.never.thrown.in.try", exc);
    4.69 +                if (exc != syms.unknownType) {
    4.70 +                    ctypes = ctypes.append(exc);
    4.71 +                    if (types.isSameType(exc, syms.objectType))
    4.72 +                        continue;
    4.73 +                    if (chk.subset(exc, caughtInTry)) {
    4.74 +                        log.error(l.head.pos(),
    4.75 +                                  "except.already.caught", exc);
    4.76 +                    } else if (!chk.isUnchecked(l.head.pos(), exc) &&
    4.77 +                               exc.tsym != syms.throwableType.tsym &&
    4.78 +                               exc.tsym != syms.exceptionType.tsym &&
    4.79 +                               !chk.intersects(exc, thrownInTry)) {
    4.80 +                        log.error(l.head.pos(),
    4.81 +                                  "except.never.thrown.in.try", exc);
    4.82 +                    }
    4.83 +                    caughtInTry = chk.incl(exc, caughtInTry);
    4.84                  }
    4.85 -                caughtInTry = chk.incl(exc, caughtInTry);
    4.86              }
    4.87              inits = initsTry.dup();
    4.88              uninits = uninitsTry.dup();
     5.1 --- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Sep 07 17:32:52 2010 +0100
     5.2 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Sep 07 17:33:43 2010 +0100
     5.3 @@ -1144,6 +1144,11 @@
     5.4                                    env.toplevel.sourcefile);
     5.5          try {
     5.6              attr.attribClass(env.tree.pos(), env.enclClass.sym);
     5.7 +            if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
     5.8 +                //if in fail-over mode, ensure that AST expression nodes
     5.9 +                //are correctly initialized (e.g. they have a type/symbol)
    5.10 +                attr.postAttr(env);
    5.11 +            }
    5.12              compileStates.put(env, CompileState.ATTR);
    5.13          }
    5.14          finally {
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/tools/javac/failover/CheckAttributedTree.java	Tue Sep 07 17:33:43 2010 +0100
     6.3 @@ -0,0 +1,775 @@
     6.4 +/*
     6.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.
    6.11 + *
    6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.15 + * version 2 for more details (a copy is included in the LICENSE file that
    6.16 + * accompanied this code).
    6.17 + *
    6.18 + * You should have received a copy of the GNU General Public License version
    6.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.21 + *
    6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.23 + * or visit www.oracle.com if you need additional information or have any
    6.24 + * questions.
    6.25 + */
    6.26 +
    6.27 +import com.sun.source.util.TaskEvent;
    6.28 +import java.awt.BorderLayout;
    6.29 +import java.awt.Color;
    6.30 +import java.awt.Dimension;
    6.31 +import java.awt.EventQueue;
    6.32 +import java.awt.Font;
    6.33 +import java.awt.GridBagConstraints;
    6.34 +import java.awt.GridBagLayout;
    6.35 +import java.awt.Rectangle;
    6.36 +import java.awt.event.ActionEvent;
    6.37 +import java.awt.event.ActionListener;
    6.38 +import java.awt.event.MouseAdapter;
    6.39 +import java.awt.event.MouseEvent;
    6.40 +import javax.swing.DefaultComboBoxModel;
    6.41 +import javax.swing.JComboBox;
    6.42 +import javax.swing.JComponent;
    6.43 +import javax.swing.JFrame;
    6.44 +import javax.swing.JLabel;
    6.45 +import javax.swing.JPanel;
    6.46 +import javax.swing.JScrollPane;
    6.47 +import javax.swing.JTextArea;
    6.48 +import javax.swing.JTextField;
    6.49 +import javax.swing.SwingUtilities;
    6.50 +import javax.swing.event.CaretEvent;
    6.51 +import javax.swing.event.CaretListener;
    6.52 +import javax.swing.text.BadLocationException;
    6.53 +import javax.swing.text.DefaultHighlighter;
    6.54 +import javax.swing.text.Highlighter;
    6.55 +import java.io.File;
    6.56 +import java.io.IOException;
    6.57 +import java.io.PrintStream;
    6.58 +import java.io.PrintWriter;
    6.59 +import java.io.StringWriter;
    6.60 +import java.lang.reflect.Field;
    6.61 +import java.lang.reflect.Modifier;
    6.62 +import java.nio.charset.Charset;
    6.63 +import java.util.ArrayList;
    6.64 +import java.util.HashMap;
    6.65 +import java.util.List;
    6.66 +import java.util.Map;
    6.67 +import javax.tools.Diagnostic;
    6.68 +import javax.tools.DiagnosticListener;
    6.69 +import javax.tools.JavaFileObject;
    6.70 +import javax.tools.StandardJavaFileManager;
    6.71 +
    6.72 +import com.sun.source.tree.CompilationUnitTree;
    6.73 +import com.sun.source.util.JavacTask;
    6.74 +import com.sun.source.util.TaskListener;
    6.75 +import com.sun.tools.javac.api.JavacTool;
    6.76 +import com.sun.tools.javac.code.Symbol;
    6.77 +import com.sun.tools.javac.code.Type;
    6.78 +import com.sun.tools.javac.tree.JCTree;
    6.79 +import com.sun.tools.javac.tree.JCTree.JCClassDecl;
    6.80 +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    6.81 +import com.sun.tools.javac.tree.JCTree.JCImport;
    6.82 +import com.sun.tools.javac.tree.TreeInfo;
    6.83 +import com.sun.tools.javac.tree.TreeScanner;
    6.84 +import com.sun.tools.javac.util.Pair;
    6.85 +
    6.86 +import java.util.Arrays;
    6.87 +import java.util.HashSet;
    6.88 +import java.util.Set;
    6.89 +import javax.lang.model.element.Element;
    6.90 +
    6.91 +/**
    6.92 + * Utility and test program to check validity of tree positions for tree nodes.
    6.93 + * The program can be run standalone, or as a jtreg test.  In standalone mode,
    6.94 + * errors can be displayed in a gui viewer. For info on command line args,
    6.95 + * run program with no args.
    6.96 + *
    6.97 + * <p>
    6.98 + * jtreg: Note that by using the -r switch in the test description below, this test
    6.99 + * will process all java files in the langtools/test directory, thus implicitly
   6.100 + * covering any new language features that may be tested in this test suite.
   6.101 + */
   6.102 +
   6.103 +/*
   6.104 + * @test
   6.105 + * @bug 6970584
   6.106 + * @summary assorted position errors in compiler syntax trees
   6.107 + * @run main CheckAttributedTree -q -r -et ERRONEOUS .
   6.108 + */
   6.109 +public class CheckAttributedTree {
   6.110 +    /**
   6.111 +     * Main entry point.
   6.112 +     * If test.src is set, program runs in jtreg mode, and will throw an Error
   6.113 +     * if any errors arise, otherwise System.exit will be used, unless the gui
   6.114 +     * viewer is being used. In jtreg mode, the default base directory for file
   6.115 +     * args is the value of ${test.src}. In jtreg mode, the -r option can be
   6.116 +     * given to change the default base directory to the root test directory.
   6.117 +     */
   6.118 +    public static void main(String... args) {
   6.119 +        String testSrc = System.getProperty("test.src");
   6.120 +        File baseDir = (testSrc == null) ? null : new File(testSrc);
   6.121 +        boolean ok = new CheckAttributedTree().run(baseDir, args);
   6.122 +        if (!ok) {
   6.123 +            if (testSrc != null)  // jtreg mode
   6.124 +                throw new Error("failed");
   6.125 +            else
   6.126 +                System.exit(1);
   6.127 +        }
   6.128 +    }
   6.129 +
   6.130 +    /**
   6.131 +     * Run the program. A base directory can be provided for file arguments.
   6.132 +     * In jtreg mode, the -r option can be given to change the default base
   6.133 +     * directory to the test root directory. For other options, see usage().
   6.134 +     * @param baseDir base directory for any file arguments.
   6.135 +     * @param args command line args
   6.136 +     * @return true if successful or in gui mode
   6.137 +     */
   6.138 +    boolean run(File baseDir, String... args) {
   6.139 +        if (args.length == 0) {
   6.140 +            usage(System.out);
   6.141 +            return true;
   6.142 +        }
   6.143 +
   6.144 +        List<File> files = new ArrayList<File>();
   6.145 +        for (int i = 0; i < args.length; i++) {
   6.146 +            String arg = args[i];
   6.147 +            if (arg.equals("-encoding") && i + 1 < args.length)
   6.148 +                encoding = args[++i];
   6.149 +            else if (arg.equals("-gui"))
   6.150 +                gui = true;
   6.151 +            else if (arg.equals("-q"))
   6.152 +                quiet = true;
   6.153 +            else if (arg.equals("-v"))
   6.154 +                verbose = true;
   6.155 +            else if (arg.equals("-t") && i + 1 < args.length)
   6.156 +                tags.add(args[++i]);
   6.157 +            else if (arg.equals("-ef") && i + 1 < args.length)
   6.158 +                excludeFiles.add(new File(baseDir, args[++i]));
   6.159 +            else if (arg.equals("-et") && i + 1 < args.length)
   6.160 +                excludeTags.add(args[++i]);
   6.161 +            else if (arg.equals("-r")) {
   6.162 +                if (excludeFiles.size() > 0)
   6.163 +                    throw new Error("-r must be used before -ef");
   6.164 +                File d = baseDir;
   6.165 +                while (!new File(d, "TEST.ROOT").exists()) {
   6.166 +                    if (d == null)
   6.167 +                        throw new Error("cannot find TEST.ROOT");
   6.168 +                    d = d.getParentFile();
   6.169 +                }
   6.170 +                baseDir = d;
   6.171 +            }
   6.172 +            else if (arg.startsWith("-"))
   6.173 +                throw new Error("unknown option: " + arg);
   6.174 +            else {
   6.175 +                while (i < args.length)
   6.176 +                    files.add(new File(baseDir, args[i++]));
   6.177 +            }
   6.178 +        }
   6.179 +
   6.180 +        for (File file: files) {
   6.181 +            if (file.exists())
   6.182 +                test(file);
   6.183 +            else
   6.184 +                error("File not found: " + file);
   6.185 +        }
   6.186 +
   6.187 +        if (fileCount != 1)
   6.188 +            System.err.println(fileCount + " files read");
   6.189 +        if (errors > 0)
   6.190 +            System.err.println(errors + " errors");
   6.191 +
   6.192 +        return (gui || errors == 0);
   6.193 +    }
   6.194 +
   6.195 +    /**
   6.196 +     * Print command line help.
   6.197 +     * @param out output stream
   6.198 +     */
   6.199 +    void usage(PrintStream out) {
   6.200 +        out.println("Usage:");
   6.201 +        out.println("  java CheckAttributedTree options... files...");
   6.202 +        out.println("");
   6.203 +        out.println("where options include:");
   6.204 +        out.println("-q        Quiet: don't report on inapplicable files");
   6.205 +        out.println("-gui      Display returns in a GUI viewer");
   6.206 +        out.println("-v        Verbose: report on files as they are being read");
   6.207 +        out.println("-t tag    Limit checks to tree nodes with this tag");
   6.208 +        out.println("          Can be repeated if desired");
   6.209 +        out.println("-ef file  Exclude file or directory");
   6.210 +        out.println("-et tag   Exclude tree nodes with given tag name");
   6.211 +        out.println("");
   6.212 +        out.println("files may be directories or files");
   6.213 +        out.println("directories will be scanned recursively");
   6.214 +        out.println("non java files, or java files which cannot be parsed, will be ignored");
   6.215 +        out.println("");
   6.216 +    }
   6.217 +
   6.218 +    /**
   6.219 +     * Test a file. If the file is a directory, it will be recursively scanned
   6.220 +     * for java files.
   6.221 +     * @param file the file or directory to test
   6.222 +     */
   6.223 +    void test(File file) {
   6.224 +        if (excludeFiles.contains(file)) {
   6.225 +            if (!quiet)
   6.226 +                error("File " + file + " excluded");
   6.227 +            return;
   6.228 +        }
   6.229 +
   6.230 +        if (file.isDirectory()) {
   6.231 +            for (File f: file.listFiles()) {
   6.232 +                test(f);
   6.233 +            }
   6.234 +            return;
   6.235 +        }
   6.236 +
   6.237 +        if (file.isFile() && file.getName().endsWith(".java")) {
   6.238 +            try {
   6.239 +                if (verbose)
   6.240 +                    System.err.println(file);
   6.241 +                fileCount++;
   6.242 +                NPETester p = new NPETester();
   6.243 +                p.test(read(file));
   6.244 +            } catch (AttributionException e) {
   6.245 +                if (!quiet) {
   6.246 +                    error("Error attributing " + file + "\n" + e.getMessage());
   6.247 +                }
   6.248 +            } catch (IOException e) {
   6.249 +                error("Error reading " + file + ": " + e);
   6.250 +            }
   6.251 +            return;
   6.252 +        }
   6.253 +
   6.254 +        if (!quiet)
   6.255 +            error("File " + file + " ignored");
   6.256 +    }
   6.257 +
   6.258 +    /**
   6.259 +     * Read a file.
   6.260 +     * @param file the file to be read
   6.261 +     * @return the tree for the content of the file
   6.262 +     * @throws IOException if any IO errors occur
   6.263 +     * @throws TreePosTest.ParseException if any errors occur while parsing the file
   6.264 +     */
   6.265 +    List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
   6.266 +        StringWriter sw = new StringWriter();
   6.267 +        PrintWriter pw = new PrintWriter(sw);
   6.268 +        Reporter r = new Reporter(pw);
   6.269 +        JavacTool tool = JavacTool.create();
   6.270 +        Charset cs = (encoding == null ? null : Charset.forName(encoding));
   6.271 +        StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
   6.272 +        Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
   6.273 +        String[] opts = { "-XDshouldStopPolicy=ATTR", "-XDverboseCompilePolicy" };
   6.274 +        JavacTask task = tool.getTask(pw, fm, r, Arrays.asList(opts), null, files);
   6.275 +        final List<Element> analyzedElems = new ArrayList<>();
   6.276 +        task.setTaskListener(new TaskListener() {
   6.277 +            public void started(TaskEvent e) {
   6.278 +                if (e.getKind() == TaskEvent.Kind.ANALYZE)
   6.279 +                        analyzedElems.add(e.getTypeElement());
   6.280 +            }
   6.281 +            public void finished(TaskEvent e) { }
   6.282 +        });
   6.283 +
   6.284 +        try {
   6.285 +            Iterable<? extends CompilationUnitTree> trees = task.parse();
   6.286 +            task.analyze();
   6.287 +            List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
   6.288 +            System.out.println("Try to add pairs. Elems are " + analyzedElems);
   6.289 +            for (CompilationUnitTree t : trees) {
   6.290 +               JCCompilationUnit cu = (JCCompilationUnit)t;
   6.291 +               for (JCTree def : cu.defs) {
   6.292 +                   if (def.getTag() == JCTree.CLASSDEF &&
   6.293 +                           analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
   6.294 +                       System.out.println("Adding pair...");
   6.295 +                       res.add(new Pair<>(cu, def));
   6.296 +                   }
   6.297 +               }
   6.298 +            }
   6.299 +            return res;
   6.300 +        }
   6.301 +        catch (Throwable t) {
   6.302 +            throw new AttributionException("Exception while attributing file: " + file);
   6.303 +        }
   6.304 +    }
   6.305 +
   6.306 +    /**
   6.307 +     * Report an error. When the program is complete, the program will either
   6.308 +     * exit or throw an Error if any errors have been reported.
   6.309 +     * @param msg the error message
   6.310 +     */
   6.311 +    void error(String msg) {
   6.312 +        System.err.println(msg);
   6.313 +        errors++;
   6.314 +    }
   6.315 +
   6.316 +    /** Number of files that have been analyzed. */
   6.317 +    int fileCount;
   6.318 +    /** Number of errors reported. */
   6.319 +    int errors;
   6.320 +    /** Flag: don't report irrelevant files. */
   6.321 +    boolean quiet;
   6.322 +    /** Flag: show errors in GUI viewer. */
   6.323 +    boolean gui;
   6.324 +    /** The GUI viewer for errors. */
   6.325 +    Viewer viewer;
   6.326 +    /** Flag: report files as they are processed. */
   6.327 +    boolean verbose;
   6.328 +    /** Option: encoding for test files. */
   6.329 +    String encoding;
   6.330 +    /** The set of tags for tree nodes to be analyzed; if empty, all tree nodes
   6.331 +     * are analyzed. */
   6.332 +    Set<String> tags = new HashSet<String>();
   6.333 +    /** Set of files and directories to be excluded from analysis. */
   6.334 +    Set<File> excludeFiles = new HashSet<File>();
   6.335 +    /** Set of tag names to be excluded from analysis. */
   6.336 +    Set<String> excludeTags = new HashSet<String>();
   6.337 +    /** Utility class for trees */
   6.338 +    TreeUtil treeUtil = new TreeUtil();
   6.339 +
   6.340 +    /**
   6.341 +     * Main class for testing assertions concerning types/symbol
   6.342 +     * left uninitialized after attribution
   6.343 +     */
   6.344 +    private class NPETester extends TreeScanner {
   6.345 +        void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
   6.346 +            for (Pair<JCCompilationUnit, JCTree> p : trees) {
   6.347 +                sourcefile = p.fst.sourcefile;
   6.348 +                endPosTable = p.fst.endPositions;
   6.349 +                encl = new Info(p.snd, endPosTable);
   6.350 +                p.snd.accept(this);
   6.351 +            }
   6.352 +        }
   6.353 +
   6.354 +        @Override
   6.355 +        public void scan(JCTree tree) {
   6.356 +            if (tree == null ||
   6.357 +                    excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) {
   6.358 +                return;
   6.359 +            }
   6.360 +
   6.361 +            Info self = new Info(tree, endPosTable);
   6.362 +            check(!mandatoryType(tree) ||
   6.363 +                    (tree.type != null &&
   6.364 +                    checkFields(tree)),
   6.365 +                    "'null' found in tree ",
   6.366 +                    self);
   6.367 +
   6.368 +            Info prevEncl = encl;
   6.369 +            encl = self;
   6.370 +            tree.accept(this);
   6.371 +            encl = prevEncl;
   6.372 +        }
   6.373 +
   6.374 +        private boolean mandatoryType(JCTree that) {
   6.375 +            return that instanceof JCTree.JCExpression ||
   6.376 +                    that.getTag() == JCTree.VARDEF ||
   6.377 +                    that.getTag() == JCTree.METHODDEF ||
   6.378 +                    that.getTag() == JCTree.CLASSDEF;
   6.379 +        }
   6.380 +
   6.381 +        private final List<String> excludedFields = Arrays.asList("varargsElement");
   6.382 +
   6.383 +        void check(boolean ok, String label, Info self) {
   6.384 +            if (!ok) {
   6.385 +                if (gui) {
   6.386 +                    if (viewer == null)
   6.387 +                        viewer = new Viewer();
   6.388 +                    viewer.addEntry(sourcefile, label, encl, self);
   6.389 +                }
   6.390 +                error(label + self.toString() + " encl: " + encl.toString() + " in file: " + sourcefile + "  " + self.tree);
   6.391 +            }
   6.392 +        }
   6.393 +
   6.394 +        boolean checkFields(JCTree t) {
   6.395 +            List<Field> fieldsToCheck = treeUtil.getFieldsOfType(t,
   6.396 +                    excludedFields,
   6.397 +                    Symbol.class,
   6.398 +                    Type.class);
   6.399 +            for (Field f : fieldsToCheck) {
   6.400 +                try {
   6.401 +                    if (f.get(t) == null) {
   6.402 +                        return false;
   6.403 +                    }
   6.404 +                }
   6.405 +                catch (IllegalAccessException e) {
   6.406 +                    System.err.println("Cannot read field: " + f);
   6.407 +                    //swallow it
   6.408 +                }
   6.409 +            }
   6.410 +            return true;
   6.411 +        }
   6.412 +
   6.413 +        @Override
   6.414 +        public void visitImport(JCImport tree) { }
   6.415 +
   6.416 +        @Override
   6.417 +        public void visitTopLevel(JCCompilationUnit tree) {
   6.418 +            scan(tree.defs);
   6.419 +        }
   6.420 +
   6.421 +        JavaFileObject sourcefile;
   6.422 +        Map<JCTree, Integer> endPosTable;
   6.423 +        Info encl;
   6.424 +    }
   6.425 +
   6.426 +    /**
   6.427 +     * Utility class providing easy access to position and other info for a tree node.
   6.428 +     */
   6.429 +    private class Info {
   6.430 +        Info() {
   6.431 +            tree = null;
   6.432 +            tag = JCTree.ERRONEOUS;
   6.433 +            start = 0;
   6.434 +            pos = 0;
   6.435 +            end = Integer.MAX_VALUE;
   6.436 +        }
   6.437 +
   6.438 +        Info(JCTree tree, Map<JCTree, Integer> endPosTable) {
   6.439 +            this.tree = tree;
   6.440 +            tag = tree.getTag();
   6.441 +            start = TreeInfo.getStartPos(tree);
   6.442 +            pos = tree.pos;
   6.443 +            end = TreeInfo.getEndPos(tree, endPosTable);
   6.444 +        }
   6.445 +
   6.446 +        @Override
   6.447 +        public String toString() {
   6.448 +            return treeUtil.nameFromTag(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]";
   6.449 +        }
   6.450 +
   6.451 +        final JCTree tree;
   6.452 +        final int tag;
   6.453 +        final int start;
   6.454 +        final int pos;
   6.455 +        final int end;
   6.456 +    }
   6.457 +
   6.458 +    /**
   6.459 +     * Names for tree tags.
   6.460 +     * javac does not provide an API to convert tag values to strings, so this class uses
   6.461 +     * reflection to determine names of public static final int values in JCTree.
   6.462 +     */
   6.463 +    private static class TreeUtil {
   6.464 +        String nameFromTag(int tag) {
   6.465 +            if (names == null) {
   6.466 +                names = new HashMap<Integer, String>();
   6.467 +                Class c = JCTree.class;
   6.468 +                for (Field f : c.getDeclaredFields()) {
   6.469 +                    if (f.getType().equals(int.class)) {
   6.470 +                        int mods = f.getModifiers();
   6.471 +                        if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
   6.472 +                            try {
   6.473 +                                names.put(f.getInt(null), f.getName());
   6.474 +                            } catch (IllegalAccessException e) {
   6.475 +                            }
   6.476 +                        }
   6.477 +                    }
   6.478 +                }
   6.479 +            }
   6.480 +            String name = names.get(tag);
   6.481 +            return (name == null) ? "??" : name;
   6.482 +        }
   6.483 +
   6.484 +        List<Field> getFieldsOfType(JCTree t, List<String> excludeNames, Class<?>... types) {
   6.485 +            List<Field> buf = new ArrayList<Field>();
   6.486 +            for (Field f : t.getClass().getDeclaredFields()) {
   6.487 +                if (!excludeNames.contains(f.getName())) {
   6.488 +                    for (Class<?> type : types) {
   6.489 +                        if (type.isAssignableFrom(f.getType())) {
   6.490 +                            f.setAccessible(true);
   6.491 +                            buf.add(f);
   6.492 +                            break;
   6.493 +                        }
   6.494 +                    }
   6.495 +                }
   6.496 +            }
   6.497 +            return buf;
   6.498 +        }
   6.499 +
   6.500 +        private Map<Integer, String> names;
   6.501 +    }
   6.502 +
   6.503 +    /**
   6.504 +     * Thrown when errors are found parsing a java file.
   6.505 +     */
   6.506 +    private static class ParseException extends Exception {
   6.507 +        ParseException(String msg) {
   6.508 +            super(msg);
   6.509 +        }
   6.510 +    }
   6.511 +
   6.512 +    private static class AttributionException extends Exception {
   6.513 +        AttributionException(String msg) {
   6.514 +            super(msg);
   6.515 +        }
   6.516 +    }
   6.517 +
   6.518 +    /**
   6.519 +     * DiagnosticListener to report diagnostics and count any errors that occur.
   6.520 +     */
   6.521 +    private static class Reporter implements DiagnosticListener<JavaFileObject> {
   6.522 +        Reporter(PrintWriter out) {
   6.523 +            this.out = out;
   6.524 +        }
   6.525 +
   6.526 +        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   6.527 +            out.println(diagnostic);
   6.528 +            switch (diagnostic.getKind()) {
   6.529 +                case ERROR:
   6.530 +                    errors++;
   6.531 +            }
   6.532 +        }
   6.533 +        int errors;
   6.534 +        PrintWriter out;
   6.535 +    }
   6.536 +
   6.537 +    /**
   6.538 +     * GUI viewer for issues found by TreePosTester. The viewer provides a drop
   6.539 +     * down list for selecting error conditions, a header area providing details
   6.540 +     * about an error, and a text area with the ranges of text highlighted as
   6.541 +     * appropriate.
   6.542 +     */
   6.543 +    private class Viewer extends JFrame {
   6.544 +        /**
   6.545 +         * Create a viewer.
   6.546 +         */
   6.547 +        Viewer() {
   6.548 +            initGUI();
   6.549 +        }
   6.550 +
   6.551 +        /**
   6.552 +         * Add another entry to the list of errors.
   6.553 +         * @param file The file containing the error
   6.554 +         * @param check The condition that was being tested, and which failed
   6.555 +         * @param encl the enclosing tree node
   6.556 +         * @param self the tree node containing the error
   6.557 +         */
   6.558 +        void addEntry(JavaFileObject file, String check, Info encl, Info self) {
   6.559 +            Entry e = new Entry(file, check, encl, self);
   6.560 +            DefaultComboBoxModel m = (DefaultComboBoxModel) entries.getModel();
   6.561 +            m.addElement(e);
   6.562 +            if (m.getSize() == 1)
   6.563 +                entries.setSelectedItem(e);
   6.564 +        }
   6.565 +
   6.566 +        /**
   6.567 +         * Initialize the GUI window.
   6.568 +         */
   6.569 +        private void initGUI() {
   6.570 +            JPanel head = new JPanel(new GridBagLayout());
   6.571 +            GridBagConstraints lc = new GridBagConstraints();
   6.572 +            GridBagConstraints fc = new GridBagConstraints();
   6.573 +            fc.anchor = GridBagConstraints.WEST;
   6.574 +            fc.fill = GridBagConstraints.HORIZONTAL;
   6.575 +            fc.gridwidth = GridBagConstraints.REMAINDER;
   6.576 +
   6.577 +            entries = new JComboBox();
   6.578 +            entries.addActionListener(new ActionListener() {
   6.579 +                public void actionPerformed(ActionEvent e) {
   6.580 +                    showEntry((Entry) entries.getSelectedItem());
   6.581 +                }
   6.582 +            });
   6.583 +            fc.insets.bottom = 10;
   6.584 +            head.add(entries, fc);
   6.585 +            fc.insets.bottom = 0;
   6.586 +            head.add(new JLabel("check:"), lc);
   6.587 +            head.add(checkField = createTextField(80), fc);
   6.588 +            fc.fill = GridBagConstraints.NONE;
   6.589 +            head.add(setBackground(new JLabel("encl:"), enclColor), lc);
   6.590 +            head.add(enclPanel = new InfoPanel(), fc);
   6.591 +            head.add(setBackground(new JLabel("self:"), selfColor), lc);
   6.592 +            head.add(selfPanel = new InfoPanel(), fc);
   6.593 +            add(head, BorderLayout.NORTH);
   6.594 +
   6.595 +            body = new JTextArea();
   6.596 +            body.setFont(Font.decode(Font.MONOSPACED));
   6.597 +            body.addCaretListener(new CaretListener() {
   6.598 +                public void caretUpdate(CaretEvent e) {
   6.599 +                    int dot = e.getDot();
   6.600 +                    int mark = e.getMark();
   6.601 +                    if (dot == mark)
   6.602 +                        statusText.setText("dot: " + dot);
   6.603 +                    else
   6.604 +                        statusText.setText("dot: " + dot + ", mark:" + mark);
   6.605 +                }
   6.606 +            });
   6.607 +            JScrollPane p = new JScrollPane(body,
   6.608 +                    JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
   6.609 +                    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
   6.610 +            p.setPreferredSize(new Dimension(640, 480));
   6.611 +            add(p, BorderLayout.CENTER);
   6.612 +
   6.613 +            statusText = createTextField(80);
   6.614 +            add(statusText, BorderLayout.SOUTH);
   6.615 +
   6.616 +            pack();
   6.617 +            setLocationRelativeTo(null); // centered on screen
   6.618 +            setVisible(true);
   6.619 +            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   6.620 +        }
   6.621 +
   6.622 +        /** Show an entry that has been selected. */
   6.623 +        private void showEntry(Entry e) {
   6.624 +            try {
   6.625 +                // update simple fields
   6.626 +                setTitle(e.file.getName());
   6.627 +                checkField.setText(e.check);
   6.628 +                enclPanel.setInfo(e.encl);
   6.629 +                selfPanel.setInfo(e.self);
   6.630 +                // show file text with highlights
   6.631 +                body.setText(e.file.getCharContent(true).toString());
   6.632 +                Highlighter highlighter = body.getHighlighter();
   6.633 +                highlighter.removeAllHighlights();
   6.634 +                addHighlight(highlighter, e.encl, enclColor);
   6.635 +                addHighlight(highlighter, e.self, selfColor);
   6.636 +                scroll(body, getMinPos(enclPanel.info, selfPanel.info));
   6.637 +            } catch (IOException ex) {
   6.638 +                body.setText("Cannot read " + e.file.getName() + ": " + e);
   6.639 +            }
   6.640 +        }
   6.641 +
   6.642 +        /** Create a test field. */
   6.643 +        private JTextField createTextField(int width) {
   6.644 +            JTextField f = new JTextField(width);
   6.645 +            f.setEditable(false);
   6.646 +            f.setBorder(null);
   6.647 +            return f;
   6.648 +        }
   6.649 +
   6.650 +        /** Add a highlighted region based on the positions in an Info object. */
   6.651 +        private void addHighlight(Highlighter h, Info info, Color c) {
   6.652 +            int start = info.start;
   6.653 +            int end = info.end;
   6.654 +            if (start == -1 && end == -1)
   6.655 +                return;
   6.656 +            if (start == -1)
   6.657 +                start = end;
   6.658 +            if (end == -1)
   6.659 +                end = start;
   6.660 +            try {
   6.661 +                h.addHighlight(info.start, info.end,
   6.662 +                        new DefaultHighlighter.DefaultHighlightPainter(c));
   6.663 +                if (info.pos != -1) {
   6.664 +                    Color c2 = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int)(.4f * 255)); // 40%
   6.665 +                    h.addHighlight(info.pos, info.pos + 1,
   6.666 +                        new DefaultHighlighter.DefaultHighlightPainter(c2));
   6.667 +                }
   6.668 +            } catch (BadLocationException e) {
   6.669 +                e.printStackTrace();
   6.670 +            }
   6.671 +        }
   6.672 +
   6.673 +        /** Get the minimum valid position in a set of info objects. */
   6.674 +        private int getMinPos(Info... values) {
   6.675 +            int i = Integer.MAX_VALUE;
   6.676 +            for (Info info: values) {
   6.677 +                if (info.start >= 0) i = Math.min(i, info.start);
   6.678 +                if (info.pos   >= 0) i = Math.min(i, info.pos);
   6.679 +                if (info.end   >= 0) i = Math.min(i, info.end);
   6.680 +            }
   6.681 +            return (i == Integer.MAX_VALUE) ? 0 : i;
   6.682 +        }
   6.683 +
   6.684 +        /** Set the background on a component. */
   6.685 +        private JComponent setBackground(JComponent comp, Color c) {
   6.686 +            comp.setOpaque(true);
   6.687 +            comp.setBackground(c);
   6.688 +            return comp;
   6.689 +        }
   6.690 +
   6.691 +        /** Scroll a text area to display a given position near the middle of the visible area. */
   6.692 +        private void scroll(final JTextArea t, final int pos) {
   6.693 +            // Using invokeLater appears to give text a chance to sort itself out
   6.694 +            // before the scroll happens; otherwise scrollRectToVisible doesn't work.
   6.695 +            // Maybe there's a better way to sync with the text...
   6.696 +            EventQueue.invokeLater(new Runnable() {
   6.697 +                public void run() {
   6.698 +                    try {
   6.699 +                        Rectangle r = t.modelToView(pos);
   6.700 +                        JScrollPane p = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, t);
   6.701 +                        r.y = Math.max(0, r.y - p.getHeight() * 2 / 5);
   6.702 +                        r.height += p.getHeight() * 4 / 5;
   6.703 +                        t.scrollRectToVisible(r);
   6.704 +                    } catch (BadLocationException ignore) {
   6.705 +                    }
   6.706 +                }
   6.707 +            });
   6.708 +        }
   6.709 +
   6.710 +        private JComboBox entries;
   6.711 +        private JTextField checkField;
   6.712 +        private InfoPanel enclPanel;
   6.713 +        private InfoPanel selfPanel;
   6.714 +        private JTextArea body;
   6.715 +        private JTextField statusText;
   6.716 +
   6.717 +        private Color selfColor = new Color(0.f, 1.f, 0.f, 0.2f); // 20% green
   6.718 +        private Color enclColor = new Color(1.f, 0.f, 0.f, 0.2f); // 20% red
   6.719 +
   6.720 +        /** Panel to display an Info object. */
   6.721 +        private class InfoPanel extends JPanel {
   6.722 +            InfoPanel() {
   6.723 +                add(tagName = createTextField(20));
   6.724 +                add(new JLabel("start:"));
   6.725 +                add(addListener(start = createTextField(6)));
   6.726 +                add(new JLabel("pos:"));
   6.727 +                add(addListener(pos = createTextField(6)));
   6.728 +                add(new JLabel("end:"));
   6.729 +                add(addListener(end = createTextField(6)));
   6.730 +            }
   6.731 +
   6.732 +            void setInfo(Info info) {
   6.733 +                this.info = info;
   6.734 +                tagName.setText(treeUtil.nameFromTag(info.tag));
   6.735 +                start.setText(String.valueOf(info.start));
   6.736 +                pos.setText(String.valueOf(info.pos));
   6.737 +                end.setText(String.valueOf(info.end));
   6.738 +            }
   6.739 +
   6.740 +            JTextField addListener(final JTextField f) {
   6.741 +                f.addMouseListener(new MouseAdapter() {
   6.742 +                    @Override
   6.743 +                    public void mouseClicked(MouseEvent e) {
   6.744 +                        body.setCaretPosition(Integer.valueOf(f.getText()));
   6.745 +                        body.getCaret().setVisible(true);
   6.746 +                    }
   6.747 +                });
   6.748 +                return f;
   6.749 +            }
   6.750 +
   6.751 +            Info info;
   6.752 +            JTextField tagName;
   6.753 +            JTextField start;
   6.754 +            JTextField pos;
   6.755 +            JTextField end;
   6.756 +        }
   6.757 +
   6.758 +        /** Object to record information about an error to be displayed. */
   6.759 +        private class Entry {
   6.760 +            Entry(JavaFileObject file, String check, Info encl, Info self) {
   6.761 +                this.file = file;
   6.762 +                this.check = check;
   6.763 +                this.encl = encl;
   6.764 +                this.self= self;
   6.765 +            }
   6.766 +
   6.767 +            @Override
   6.768 +            public String toString() {
   6.769 +                return file.getName() + " " + check + " " + getMinPos(encl, self);
   6.770 +            }
   6.771 +
   6.772 +            final JavaFileObject file;
   6.773 +            final String check;
   6.774 +            final Info encl;
   6.775 +            final Info self;
   6.776 +        }
   6.777 +    }
   6.778 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/test/tools/javac/failover/FailOver01.java	Tue Sep 07 17:33:43 2010 +0100
     7.3 @@ -0,0 +1,10 @@
     7.4 +/*
     7.5 +  * @test /nodynamiccopyright/
     7.6 + * @bug 6970584
     7.7 + * @summary Flow.java should be more error-friendly
     7.8 + * @author mcimadamore
     7.9 + *
    7.10 + * @compile/fail/ref=FailOver01.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver01.java
    7.11 + */
    7.12 +
    7.13 +class Test { { x = "" } }
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/test/tools/javac/failover/FailOver01.out	Tue Sep 07 17:33:43 2010 +0100
     8.3 @@ -0,0 +1,3 @@
     8.4 +FailOver01.java:10:22: compiler.err.expected: ';'
     8.5 +FailOver01.java:10:16: compiler.err.cant.resolve.location: kindname.variable, x, , , kindname.class, Test
     8.6 +2 errors
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/tools/javac/failover/FailOver02.java	Tue Sep 07 17:33:43 2010 +0100
     9.3 @@ -0,0 +1,14 @@
     9.4 +/*
     9.5 + * @test /nodynamiccopyright/
     9.6 + * @bug 6970584
     9.7 + * @summary Flow.java should be more error-friendly
     9.8 + * @author mcimadamore
     9.9 + *
    9.10 + * @compile/fail/ref=FailOver02.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver02.java
    9.11 + */
    9.12 +
    9.13 +class Test implements AutoCloseable {
    9.14 +    void test() {
    9.15 +        try(Test t = null) {}
    9.16 +    }
    9.17 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/tools/javac/failover/FailOver02.out	Tue Sep 07 17:33:43 2010 +0100
    10.3 @@ -0,0 +1,3 @@
    10.4 +FailOver02.java:10:1: compiler.err.does.not.override.abstract: Test, close(), java.lang.AutoCloseable
    10.5 +FailOver02.java:12:9: compiler.err.cant.resolve.location.args: kindname.method, close, , , kindname.class, Test
    10.6 +2 errors
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/tools/javac/failover/FailOver03.java	Tue Sep 07 17:33:43 2010 +0100
    11.3 @@ -0,0 +1,12 @@
    11.4 +/*
    11.5 + * @test /nodynamiccopyright/
    11.6 + * @bug 6970584
    11.7 + * @summary Flow.java should be more error-friendly
    11.8 + * @author mcimadamore
    11.9 + *
   11.10 + * @compile/fail/ref=FailOver03.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver03.java
   11.11 + */
   11.12 +
   11.13 +class Test extends Test {
   11.14 +   Test i;
   11.15 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/tools/javac/failover/FailOver03.out	Tue Sep 07 17:33:43 2010 +0100
    12.3 @@ -0,0 +1,2 @@
    12.4 +FailOver03.java:10:1: compiler.err.cyclic.inheritance: Test
    12.5 +1 error
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/test/tools/javac/failover/FailOver04.java	Tue Sep 07 17:33:43 2010 +0100
    13.3 @@ -0,0 +1,12 @@
    13.4 +/*
    13.5 + * @test /nodynamiccopyright/
    13.6 + * @bug 6970584
    13.7 + * @summary Flow.java should be more error-friendly
    13.8 + * @author mcimadamore
    13.9 + *
   13.10 + * @compile/fail/ref=FailOver04.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver04.java
   13.11 + */
   13.12 +
   13.13 +class Test {
   13.14 +   { new Unknown() {}; }
   13.15 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/tools/javac/failover/FailOver04.out	Tue Sep 07 17:33:43 2010 +0100
    14.3 @@ -0,0 +1,2 @@
    14.4 +FailOver04.java:11:10: compiler.err.cant.resolve.location: kindname.class, Unknown, , , kindname.class, Test
    14.5 +1 error
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/tools/javac/failover/FailOver05.java	Tue Sep 07 17:33:43 2010 +0100
    15.3 @@ -0,0 +1,12 @@
    15.4 +/*
    15.5 + * @test /nodynamiccopyright/
    15.6 + * @bug 6970584
    15.7 + * @summary Flow.java should be more error-friendly
    15.8 + * @author mcimadamore
    15.9 + *
   15.10 + * @compile/fail/ref=FailOver05.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver05.java
   15.11 + */
   15.12 +
   15.13 +class Test extends Test {
   15.14 +   { for ( Integer x : null) {} }
   15.15 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/tools/javac/failover/FailOver05.out	Tue Sep 07 17:33:43 2010 +0100
    16.3 @@ -0,0 +1,2 @@
    16.4 +FailOver05.java:10:1: compiler.err.cyclic.inheritance: Test
    16.5 +1 error
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/tools/javac/failover/FailOver06.java	Tue Sep 07 17:33:43 2010 +0100
    17.3 @@ -0,0 +1,13 @@
    17.4 +/*
    17.5 + * @test /nodynamiccopyright/
    17.6 + * @bug 6970584
    17.7 + * @summary Flow.java should be more error-friendly
    17.8 + * @author mcimadamore
    17.9 + *
   17.10 + * @compile/fail/ref=FailOver06.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver06.java
   17.11 + */
   17.12 +
   17.13 +class Test extends Test {
   17.14 +    Inference x = 1;
   17.15 +    { if (x == 1) { } else { } }
   17.16 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/test/tools/javac/failover/FailOver06.out	Tue Sep 07 17:33:43 2010 +0100
    18.3 @@ -0,0 +1,2 @@
    18.4 +FailOver06.java:10:1: compiler.err.cyclic.inheritance: Test
    18.5 +1 error
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/test/tools/javac/failover/FailOver07.java	Tue Sep 07 17:33:43 2010 +0100
    19.3 @@ -0,0 +1,13 @@
    19.4 +/*
    19.5 + * @test /nodynamiccopyright/
    19.6 + * @bug 6970584
    19.7 + * @summary Flow.java should be more error-friendly
    19.8 + * @author mcimadamore
    19.9 + *
   19.10 + * @compile/fail/ref=FailOver07.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver07.java
   19.11 + */
   19.12 +
   19.13 +class Test extends Test {
   19.14 +    Integer x = 1;
   19.15 +    { do {} while (x); }
   19.16 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/tools/javac/failover/FailOver07.out	Tue Sep 07 17:33:43 2010 +0100
    20.3 @@ -0,0 +1,2 @@
    20.4 +FailOver07.java:10:1: compiler.err.cyclic.inheritance: Test
    20.5 +1 error
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/test/tools/javac/failover/FailOver08.java	Tue Sep 07 17:33:43 2010 +0100
    21.3 @@ -0,0 +1,13 @@
    21.4 +/*
    21.5 + * @test /nodynamiccopyright/
    21.6 + * @bug 6970584
    21.7 + * @summary Flow.java should be more error-friendly
    21.8 + * @author mcimadamore
    21.9 + *
   21.10 + * @compile/fail/ref=FailOver08.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver08.java
   21.11 + */
   21.12 +
   21.13 +class Test extends Test {
   21.14 +    Integer x = 1;
   21.15 +    { while (x) {}; }
   21.16 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/test/tools/javac/failover/FailOver08.out	Tue Sep 07 17:33:43 2010 +0100
    22.3 @@ -0,0 +1,2 @@
    22.4 +FailOver08.java:10:1: compiler.err.cyclic.inheritance: Test
    22.5 +1 error
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/test/tools/javac/failover/FailOver09.java	Tue Sep 07 17:33:43 2010 +0100
    23.3 @@ -0,0 +1,13 @@
    23.4 +/*
    23.5 + * @test /nodynamiccopyright/
    23.6 + * @bug 6970584
    23.7 + * @summary Flow.java should be more error-friendly
    23.8 + * @author mcimadamore
    23.9 + *
   23.10 + * @compile/fail/ref=FailOver09.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver09.java
   23.11 + */
   23.12 +
   23.13 +class Test extends Test {
   23.14 +    Integer x = 1;
   23.15 +    { for (x = 0 ; x ; x++) {}; }
   23.16 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/test/tools/javac/failover/FailOver09.out	Tue Sep 07 17:33:43 2010 +0100
    24.3 @@ -0,0 +1,2 @@
    24.4 +FailOver09.java:10:1: compiler.err.cyclic.inheritance: Test
    24.5 +1 error
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/test/tools/javac/failover/FailOver10.java	Tue Sep 07 17:33:43 2010 +0100
    25.3 @@ -0,0 +1,15 @@
    25.4 +/*
    25.5 + * @test /nodynamiccopyright/
    25.6 + * @bug 6970584
    25.7 + * @summary Flow.java should be more error-friendly
    25.8 + * @author mcimadamore
    25.9 + *
   25.10 + * @compile/fail/ref=FailOver10.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver10.java
   25.11 + */
   25.12 +
   25.13 +class Test extends Test {
   25.14 +
   25.15 +    boolean cond;
   25.16 +
   25.17 +    { Object o = null; }
   25.18 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/test/tools/javac/failover/FailOver10.out	Tue Sep 07 17:33:43 2010 +0100
    26.3 @@ -0,0 +1,2 @@
    26.4 +FailOver10.java:10:1: compiler.err.cyclic.inheritance: Test
    26.5 +1 error
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/tools/javac/failover/FailOver11.java	Tue Sep 07 17:33:43 2010 +0100
    27.3 @@ -0,0 +1,17 @@
    27.4 +/*
    27.5 + * @test /nodynamiccopyright/
    27.6 + * @bug 6970584
    27.7 + * @summary Flow.java should be more error-friendly
    27.8 + * @author mcimadamore
    27.9 + *
   27.10 + * @compile/fail/ref=FailOver11.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver11.java
   27.11 + */
   27.12 +
   27.13 +class Test extends Test {
   27.14 +
   27.15 +    boolean cond;
   27.16 +
   27.17 +    void m(Object o) {}
   27.18 +
   27.19 +    { m(cond ? null : null); }
   27.20 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/test/tools/javac/failover/FailOver11.out	Tue Sep 07 17:33:43 2010 +0100
    28.3 @@ -0,0 +1,2 @@
    28.4 +FailOver11.java:10:1: compiler.err.cyclic.inheritance: Test
    28.5 +1 error
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/test/tools/javac/failover/FailOver12.java	Tue Sep 07 17:33:43 2010 +0100
    29.3 @@ -0,0 +1,15 @@
    29.4 +/*
    29.5 + * @test /nodynamiccopyright/
    29.6 + * @bug 6970584
    29.7 + * @summary Flow.java should be more error-friendly
    29.8 + * @author mcimadamore
    29.9 + *
   29.10 + * @compile/fail/ref=FailOver12.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver12.java
   29.11 + */
   29.12 +
   29.13 +class Test extends Test {
   29.14 +
   29.15 +    Integer x = 1;
   29.16 +
   29.17 +    { try {} catch (Exception e) {} }
   29.18 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/test/tools/javac/failover/FailOver12.out	Tue Sep 07 17:33:43 2010 +0100
    30.3 @@ -0,0 +1,2 @@
    30.4 +FailOver12.java:10:1: compiler.err.cyclic.inheritance: Test
    30.5 +1 error
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/test/tools/javac/failover/FailOver13.java	Tue Sep 07 17:33:43 2010 +0100
    31.3 @@ -0,0 +1,15 @@
    31.4 +/*
    31.5 + * @test /nodynamiccopyright/
    31.6 + * @bug 6970584
    31.7 + * @summary Flow.java should be more error-friendly
    31.8 + * @author mcimadamore
    31.9 + *
   31.10 + * @compile/fail/ref=FailOver13.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver13.java
   31.11 + */
   31.12 +
   31.13 +class Test extends Test {
   31.14 +
   31.15 +    Integer x = 1;
   31.16 +
   31.17 +    { x = (Object)o; }
   31.18 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/test/tools/javac/failover/FailOver13.out	Tue Sep 07 17:33:43 2010 +0100
    32.3 @@ -0,0 +1,2 @@
    32.4 +FailOver13.java:10:1: compiler.err.cyclic.inheritance: Test
    32.5 +1 error
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/test/tools/javac/failover/FailOver14.java	Tue Sep 07 17:33:43 2010 +0100
    33.3 @@ -0,0 +1,14 @@
    33.4 +/*
    33.5 + * @test /nodynamiccopyright/
    33.6 + * @bug 6970584
    33.7 + * @summary Flow.java should be more error-friendly
    33.8 + * @author mcimadamore
    33.9 + *
   33.10 + * @compile/fail/ref=FailOver14.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver14.java
   33.11 + */
   33.12 +
   33.13 +class Test extends Test  {
   33.14 +
   33.15 +   { for (Integer x : !x) { } }
   33.16 +
   33.17 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/test/tools/javac/failover/FailOver14.out	Tue Sep 07 17:33:43 2010 +0100
    34.3 @@ -0,0 +1,2 @@
    34.4 +FailOver14.java:10:1: compiler.err.cyclic.inheritance: Test
    34.5 +1 error

mercurial