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
--- 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");
+ }
+ }
+ }
+}