8017216: javac doesn't fill in end position for some errors of type not found
authorksrini
Fri, 19 Jul 2013 07:22:53 -0700
changeset 19122 1841f2fa76de
parent 19121 c626ed0c6ab0
child 19123 50733e28eaca
8017216: javac doesn't fill in end position for some errors of type not found 8019421: Javac doesn't fill in end position for some annotation related errors 8019422: Javac doesn't fill in end position for uninitialized variable errors Reviewed-by: jjg, mcimadamore
langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java
langtools/test/tools/javac/diags/examples/VarNotIntializedInDefaultConstructor.java
langtools/test/tools/javac/positions/TreeEndPosTest.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Jul 17 19:16:12 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Fri Jul 19 07:22:53 2013 -0700
@@ -273,7 +273,7 @@
                 continue;
             }
             JCIdent left = (JCIdent)assign.lhs;
-            Symbol method = rs.resolveQualifiedMethod(left.pos(),
+            Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(),
                                                           env,
                                                           a.type,
                                                           left.name,
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 17 19:16:12 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jul 19 07:22:53 2013 -0700
@@ -1948,6 +1948,8 @@
             clazzid1 = make.at(clazz.pos).Select(make.Type(encltype),
                                                  ((JCIdent) clazzid).name);
 
+            EndPosTable endPosTable = this.env.toplevel.endPositions;
+            endPosTable.storeEnd(clazzid1, tree.getEndPosition(endPosTable));
             if (clazz.hasTag(ANNOTATED_TYPE)) {
                 JCAnnotatedType annoType = (JCAnnotatedType) clazz;
                 List<JCAnnotation> annos = annoType.annotations;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Jul 17 19:16:12 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Jul 19 07:22:53 2013 -0700
@@ -1339,7 +1339,7 @@
 
         /** A mapping from addresses to variable symbols.
          */
-        VarSymbol[] vars;
+        JCVariableDecl[] vardecls;
 
         /** The current class being defined.
          */
@@ -1417,13 +1417,14 @@
          *  to the next available sequence number and entering it under that
          *  index into the vars array.
          */
-        void newVar(VarSymbol sym) {
-            vars = ArrayUtils.ensureCapacity(vars, nextadr);
+        void newVar(JCVariableDecl varDecl) {
+            VarSymbol sym = varDecl.sym;
+            vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
             if ((sym.flags() & FINAL) == 0) {
                 sym.flags_field |= EFFECTIVELY_FINAL;
             }
             sym.adr = nextadr;
-            vars[nextadr] = sym;
+            vardecls[nextadr] = varDecl;
             inits.excl(nextadr);
             uninits.incl(nextadr);
             nextadr++;
@@ -1493,11 +1494,13 @@
         /** Check that trackable variable is initialized.
          */
         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
+            checkInit(pos, sym, "var.might.not.have.been.initialized");
+        }
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
                 trackable(sym) &&
                 !inits.isMember(sym.adr)) {
-                log.error(pos, "var.might.not.have.been.initialized",
-                          sym);
+                log.error(pos, errkey, sym);
                 inits.incl(sym.adr);
             }
         }
@@ -1599,7 +1602,7 @@
                         if ((def.mods.flags & STATIC) != 0) {
                             VarSymbol sym = def.sym;
                             if (trackable(sym))
-                                newVar(sym);
+                                newVar(def);
                         }
                     }
                 }
@@ -1619,7 +1622,7 @@
                         if ((def.mods.flags & STATIC) == 0) {
                             VarSymbol sym = def.sym;
                             if (trackable(sym))
-                                newVar(sym);
+                                newVar(def);
                         }
                     }
                 }
@@ -1678,9 +1681,22 @@
                 scan(tree.body);
 
                 if (isInitialConstructor) {
-                    for (int i = firstadr; i < nextadr; i++)
-                        if (vars[i].owner == classDef.sym)
-                            checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
+                    boolean isSynthesized = (tree.sym.flags() &
+                                             GENERATEDCONSTR) != 0;
+                    for (int i = firstadr; i < nextadr; i++) {
+                        JCVariableDecl vardecl = vardecls[i];
+                        VarSymbol var = vardecl.sym;
+                        if (var.owner == classDef.sym) {
+                            // choose the diagnostic position based on whether
+                            // the ctor is default(synthesized) or not
+                            if (isSynthesized) {
+                                checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
+                                    var, "var.not.initialized.in.default.constructor");
+                            } else {
+                                checkInit(TreeInfo.diagEndPos(tree.body), var);
+                            }
+                        }
+                    }
                 }
                 List<AssignPendingExit> exits = pendingExits.toList();
                 pendingExits = new ListBuffer<AssignPendingExit>();
@@ -1691,7 +1707,7 @@
                     if (isInitialConstructor) {
                         inits.assign(exit.exit_inits);
                         for (int i = firstadr; i < nextadr; i++)
-                            checkInit(exit.tree.pos(), vars[i]);
+                            checkInit(exit.tree.pos(), vardecls[i].sym);
                     }
                 }
             } finally {
@@ -1706,7 +1722,7 @@
 
         public void visitVarDef(JCVariableDecl tree) {
             boolean track = trackable(tree.sym);
-            if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
+            if (track && tree.sym.owner.kind == MTH) newVar(tree);
             if (tree.init != null) {
                 Lint lintPrev = lint;
                 lint = lint.augment(tree.sym);
@@ -2239,11 +2255,11 @@
                 Flow.this.make = make;
                 startPos = tree.pos().getStartPosition();
 
-                if (vars == null)
-                    vars = new VarSymbol[32];
+                if (vardecls == null)
+                    vardecls = new JCVariableDecl[32];
                 else
-                    for (int i=0; i<vars.length; i++)
-                        vars[i] = null;
+                    for (int i=0; i<vardecls.length; i++)
+                        vardecls[i] = null;
                 firstadr = 0;
                 nextadr = 0;
                 pendingExits = new ListBuffer<AssignPendingExit>();
@@ -2255,8 +2271,8 @@
                 startPos = -1;
                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
-                if (vars != null) for (int i=0; i<vars.length; i++)
-                    vars[i] = null;
+                if (vardecls != null) for (int i=0; i<vardecls.length; i++)
+                    vardecls[i] = null;
                 firstadr = 0;
                 nextadr = 0;
                 pendingExits = null;
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Jul 17 19:16:12 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jul 19 07:22:53 2013 -0700
@@ -4053,7 +4053,7 @@
             endPosMap = new HashMap<JCTree, Integer>();
         }
 
-        protected void storeEnd(JCTree tree, int endpos) {
+        public void storeEnd(JCTree tree, int endpos) {
             endPosMap.put(tree, errorEndPos > endpos ? errorEndPos : endpos);
         }
 
@@ -4091,7 +4091,7 @@
             super(parser);
         }
 
-        protected void storeEnd(JCTree tree, int endpos) { /* empty */ }
+        public void storeEnd(JCTree tree, int endpos) { /* empty */ }
 
         protected <T extends JCTree> T to(T t) {
             return t;
@@ -4127,14 +4127,6 @@
         }
 
         /**
-         * Store ending position for a tree, the value of which is the greater
-         * of last error position and the given ending position.
-         * @param tree   The tree.
-         * @param endpos The ending position to associate with the tree.
-         */
-        protected abstract void storeEnd(JCTree tree, int endpos);
-
-        /**
          * Store current token's ending position for a tree, the value of which
          * will be the greater of last error position and the ending position of
          * the current token.
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 17 19:16:12 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Jul 19 07:22:53 2013 -0700
@@ -1069,6 +1069,10 @@
     variable {0} might not have been initialized
 
 # 0: symbol
+compiler.err.var.not.initialized.in.default.constructor=\
+    variable {0} not initialized in the default constructor
+
+# 0: symbol
 compiler.err.var.might.be.assigned.in.loop=\
     variable {0} might be assigned in loop
 
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java	Wed Jul 17 19:16:12 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java	Fri Jul 19 07:22:53 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -43,10 +43,17 @@
     public int getEndPos(JCTree tree);
 
     /**
+     * Store ending position for a tree, the value of which is the greater of
+     * last error position and the given ending position.
+     * @param tree The tree.
+     * @param endpos The ending position to associate with the tree.
+     */
+    public abstract void storeEnd(JCTree tree, int endpos);
+
+    /**
      * Give an old tree and a new tree, the old tree will be replaced with
      * the new tree, the position of the new tree will be that of the old
      * tree.
-     * not exist.
      * @param oldtree a JCTree to be replaced
      * @param newtree a JCTree to be replaced with
      * @return position of the old tree or Positions.NOPOS for non-existent mapping
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/VarNotIntializedInDefaultConstructor.java	Fri Jul 19 07:22:53 2013 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+// key: compiler.err.var.not.initialized.in.default.constructor
+
+class X {
+    final int j;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/positions/TreeEndPosTest.java	Fri Jul 19 07:22:53 2013 -0700
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2013, 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 8017216 8019422 8019421
+ * @summary verify start and end positions
+ * @run main TreeEndPosTest
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class TreeEndPosTest {
+    private static JavaFileManager getJavaFileManager(JavaCompiler compiler,
+            DiagnosticCollector dc) {
+        return compiler.getStandardFileManager(dc, null, null);
+    }
+
+    static class JavaSource extends SimpleJavaFileObject {
+
+        final String source;
+        int startPos;
+        int endPos;
+
+        private JavaSource(String filename, String source) {
+            super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
+            this.source = source;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+
+        static JavaSource createJavaSource(String preamble, String body,
+                String postamble, String expected) {
+            JavaSource js = createJavaSource(preamble, body, postamble, -1, -1);
+            js.startPos = js.source.indexOf(expected);
+            js.endPos   = js.startPos + expected.length();
+            return js;
+        }
+
+        static JavaSource createJavaSource(String body, String expected) {
+            return createJavaSource(null, body, null, expected);
+        }
+
+        private static JavaSource createJavaSource(String preamble, String body,
+                String postamble, int start, int end) {
+            final String name = "Bug";
+            StringBuilder code = new StringBuilder();
+            if (preamble != null) {
+                code.append(preamble);
+            }
+            code.append("public class " + name + "{");
+            if (body != null) {
+                code.append(body);
+            }
+            code.append("}");
+            if (postamble != null) {
+                code.append(postamble);
+            }
+            JavaSource js = new JavaSource(name + ".java", code.toString());
+            js.startPos = start;
+            js.endPos = end;
+            return js;
+        }
+    }
+
+    public static void main(String... args) throws IOException {
+        testUninitializedVariable();
+        testMissingAnnotationValue();
+        testFinalVariableWithDefaultConstructor();
+        testFinalVariableWithConstructor();
+    }
+
+    static void testUninitializedVariable() throws IOException {
+        compile(JavaSource.createJavaSource("Object o = new A().new B(); class A { }",
+                "B()"));
+    }
+    static void testMissingAnnotationValue() throws IOException {
+        compile(JavaSource.createJavaSource("@Foo(\"vvvv\")",
+                null, "@interface Foo { }", "\"vvvv\""));
+    }
+
+    static void testFinalVariableWithDefaultConstructor() throws IOException {
+        compile(JavaSource.createJavaSource("private static final String Foo; public void bar() { }",
+                "private static final String Foo;"));
+    }
+
+    static void testFinalVariableWithConstructor() throws IOException {
+        compile(JavaSource.createJavaSource("public Bug (){} private static final String Foo; public void bar() { }",
+                "{}"));
+    }
+
+    static void compile(JavaSource src) throws IOException {
+        ByteArrayOutputStream ba = new ByteArrayOutputStream();
+        PrintWriter writer = new PrintWriter(ba);
+        File tempDir = new File(".");
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        DiagnosticCollector dc = new DiagnosticCollector();
+        JavaFileManager javaFileManager = getJavaFileManager(compiler, dc);
+        List<String> options = new ArrayList<>();
+        options.add("-cp");
+        options.add(tempDir.getPath());
+        options.add("-d");
+        options.add(tempDir.getPath());
+        options.add("-XDshouldStopPolicy=GENERATE");
+
+        List<JavaFileObject> sources = new ArrayList<>();
+        sources.add(src);
+        JavaCompiler.CompilationTask task =
+                compiler.getTask(writer, javaFileManager,
+                dc, options, null,
+                sources);
+        task.call();
+        for (Diagnostic diagnostic : (List<Diagnostic>) dc.getDiagnostics()) {
+            long actualStart = diagnostic.getStartPosition();
+            long actualEnd = diagnostic.getEndPosition();
+            System.out.println("Source: " + src.source);
+            System.out.println("Diagnostic: " + diagnostic);
+            System.out.print("Start position: Expected: " + src.startPos);
+            System.out.println(", Actual: " + actualStart);
+            System.out.print("End position: Expected: " + src.endPos);
+            System.out.println(", Actual: " + actualEnd);
+            if (src.startPos != actualStart || src.endPos != actualEnd) {
+                throw new RuntimeException("error: trees don't match");
+            }
+        }
+    }
+}