From 82c8d34d1180a0b19918f9d1897cbc51ab690dc1 Mon Sep 17 00:00:00 2001 From: ksrini Date: Fri, 19 Jul 2013 07:22:53 -0700 Subject: [PATCH] 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 --- .../com/sun/tools/javac/comp/Annotate.java | 2 +- .../com/sun/tools/javac/comp/Attr.java | 2 + .../com/sun/tools/javac/comp/Flow.java | 54 ++++-- .../sun/tools/javac/parser/JavacParser.java | 12 +- .../tools/javac/resources/compiler.properties | 4 + .../com/sun/tools/javac/tree/EndPosTable.java | 11 +- .../VarNotIntializedInDefaultConstructor.java | 28 +++ .../tools/javac/positions/TreeEndPosTest.java | 163 ++++++++++++++++++ 8 files changed, 244 insertions(+), 32 deletions(-) create mode 100644 test/tools/javac/diags/examples/VarNotIntializedInDefaultConstructor.java create mode 100644 test/tools/javac/positions/TreeEndPosTest.java diff --git a/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/share/classes/com/sun/tools/javac/comp/Annotate.java index ebc6fa33..39587558 100644 --- a/src/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -273,7 +273,7 @@ public class Annotate { continue; } JCIdent left = (JCIdent)assign.lhs; - Symbol method = rs.resolveQualifiedMethod(left.pos(), + Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(), env, a.type, left.name, diff --git a/src/share/classes/com/sun/tools/javac/comp/Attr.java b/src/share/classes/com/sun/tools/javac/comp/Attr.java index 20bfc25d..1c33d306 100644 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1948,6 +1948,8 @@ public class Attr extends JCTree.Visitor { 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 annos = annoType.annotations; diff --git a/src/share/classes/com/sun/tools/javac/comp/Flow.java b/src/share/classes/com/sun/tools/javac/comp/Flow.java index dbab4de3..10ff59c4 100644 --- a/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -1339,7 +1339,7 @@ public class Flow { /** A mapping from addresses to variable symbols. */ - VarSymbol[] vars; + JCVariableDecl[] vardecls; /** The current class being defined. */ @@ -1417,13 +1417,14 @@ public class Flow { * 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 @@ public class Flow { /** 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 @@ public class Flow { if ((def.mods.flags & STATIC) != 0) { VarSymbol sym = def.sym; if (trackable(sym)) - newVar(sym); + newVar(def); } } } @@ -1619,7 +1622,7 @@ public class Flow { if ((def.mods.flags & STATIC) == 0) { VarSymbol sym = def.sym; if (trackable(sym)) - newVar(sym); + newVar(def); } } } @@ -1678,9 +1681,22 @@ public class Flow { 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 exits = pendingExits.toList(); pendingExits = new ListBuffer(); @@ -1691,7 +1707,7 @@ public class Flow { 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 class Flow { 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 @@ public class Flow { 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(); @@ -2255,8 +2271,8 @@ public class Flow { startPos = -1; resetBits(inits, uninits, uninitsTry, initsWhenTrue, initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse); - if (vars != null) for (int i=0; i(); } - 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 @@ public class JavacParser implements Parser { super(parser); } - protected void storeEnd(JCTree tree, int endpos) { /* empty */ } + public void storeEnd(JCTree tree, int endpos) { /* empty */ } protected T to(T t) { return t; @@ -4126,14 +4126,6 @@ public class JavacParser implements Parser { this.parser = parser; } - /** - * 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 diff --git a/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 2487b7be..40f94c9a 100644 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1068,6 +1068,10 @@ compiler.err.var.might.already.be.assigned=\ compiler.err.var.might.not.have.been.initialized=\ 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 diff --git a/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java b/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java index 1f9eefa5..d68ba838 100644 --- a/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java +++ b/src/share/classes/com/sun/tools/javac/tree/EndPosTable.java @@ -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 @@ -42,11 +42,18 @@ public interface EndPosTable { */ 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 diff --git a/test/tools/javac/diags/examples/VarNotIntializedInDefaultConstructor.java b/test/tools/javac/diags/examples/VarNotIntializedInDefaultConstructor.java new file mode 100644 index 00000000..91f44a35 --- /dev/null +++ b/test/tools/javac/diags/examples/VarNotIntializedInDefaultConstructor.java @@ -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; +} diff --git a/test/tools/javac/positions/TreeEndPosTest.java b/test/tools/javac/positions/TreeEndPosTest.java new file mode 100644 index 00000000..96180376 --- /dev/null +++ b/test/tools/javac/positions/TreeEndPosTest.java @@ -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 options = new ArrayList<>(); + options.add("-cp"); + options.add(tempDir.getPath()); + options.add("-d"); + options.add(tempDir.getPath()); + options.add("-XDshouldStopPolicy=GENERATE"); + + List sources = new ArrayList<>(); + sources.add(src); + JavaCompiler.CompilationTask task = + compiler.getTask(writer, javaFileManager, + dc, options, null, + sources); + task.call(); + for (Diagnostic diagnostic : (List) 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"); + } + } + } +} -- GitLab