Thu, 03 Feb 2011 09:36:28 +0000
5017953: spurious cascaded diagnostics when name not found
Summary: when an operator is applied to one or more erroneous operands, spurious diagnostics are generated
Reviewed-by: jjg
1 /*
2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
24 import java.io.*;
25 import java.util.*;
26 import javax.lang.model.util.*;
27 import javax.tools.*;
28 import com.sun.tools.javac.api.*;
29 import com.sun.source.tree.*;
30 import com.sun.source.util.*;
31 import com.sun.tools.javac.tree.JCTree;
32 import com.sun.tools.javac.tree.JCTree.*;
33 import com.sun.tools.javac.util.Position;
35 /*
36 * Abstract class to help check the scopes in a parsed source file.
37 * -- parse source file
38 * -- scan trees looking for string literals
39 * -- check the scope at that point against the string, using
40 * boolean check(Scope s, String ref)
41 */
42 abstract class Checker {
43 // parse the source file and call check(scope, string) for each string literal found
44 void check(String... fileNames) throws IOException {
45 File testSrc = new File(System.getProperty("test.src"));
47 DiagnosticListener<JavaFileObject> dl = new DiagnosticListener<JavaFileObject>() {
48 public void report(Diagnostic d) {
49 System.err.println(d);
50 if (d.getKind() == Diagnostic.Kind.ERROR)
51 errors = true;
52 new Exception().printStackTrace();
53 }
54 };
56 JavacTool tool = JavacTool.create();
57 StandardJavaFileManager fm = tool.getStandardFileManager(dl, null, null);
58 Iterable<? extends JavaFileObject> files =
59 fm.getJavaFileObjectsFromFiles(getFiles(testSrc, fileNames));
60 task = tool.getTask(null, fm, dl, null, null, files);
61 Iterable<? extends CompilationUnitTree> units = task.parse();
63 if (errors)
64 throw new AssertionError("errors occurred creating trees");
66 ScopeScanner s = new ScopeScanner();
67 for (CompilationUnitTree unit: units) {
68 TreePath p = new TreePath(unit);
69 s.scan(p, getTrees());
70 }
71 task = null;
73 if (errors)
74 throw new AssertionError("errors occurred checking scopes");
75 }
77 // default impl: split ref at ";" and call checkLocal(scope, ref_segment) on scope and its enclosing scopes
78 protected boolean check(Scope s, String ref) {
79 // System.err.println("check scope: " + s);
80 // System.err.println("check ref: " + ref);
81 if (s == null && (ref == null || ref.trim().length() == 0))
82 return true;
84 if (s == null) {
85 error(s, ref, "scope missing");
86 return false;
87 }
89 if (ref == null) {
90 error(s, ref, "scope unexpected");
91 return false;
92 }
94 String local;
95 String encl;
96 int semi = ref.indexOf(';');
97 if (semi == -1) {
98 local = ref;
99 encl = null;
100 } else {
101 local = ref.substring(0, semi);
102 encl = ref.substring(semi + 1);
103 }
105 return checkLocal(s, local.trim())
106 & check(s.getEnclosingScope(), encl);
107 }
109 // override if using default check(Scope,String)
110 boolean checkLocal(Scope s, String ref) {
111 throw new IllegalStateException();
112 }
114 void error(Scope s, String ref, String msg) {
115 System.err.println("Error: " + msg);
116 System.err.println("Scope: " + (s == null ? null : asList(s.getLocalElements())));
117 System.err.println("Expect: " + ref);
118 System.err.println("javac: " + (s == null ? null : ((JavacScope) s).getEnv()));
119 errors = true;
120 }
122 protected Elements getElements() {
123 return task.getElements();
124 }
126 protected Trees getTrees() {
127 return Trees.instance(task);
128 }
130 boolean errors = false;
131 protected JavacTask task;
133 // scan a parse tree, and for every string literal found, call check(scope, string) with
134 // the string value at the scope at that point
135 class ScopeScanner extends TreePathScanner<Boolean,Trees> {
136 public Boolean visitLiteral(LiteralTree tree, Trees trees) {
137 TreePath path = getCurrentPath();
138 CompilationUnitTree unit = path.getCompilationUnit();
139 Position.LineMap lineMap = ((JCCompilationUnit)unit).lineMap;
140 // long line = lineMap.getLineNumber(((JCTree)tree).pos/*trees.getSourcePositions().getStartPosition(tree)*/);
141 // System.err.println(line + ": " + abbrev(tree));
142 Scope s = trees.getScope(path);
143 if (tree.getKind() == Tree.Kind.STRING_LITERAL)
144 check(s, tree.getValue().toString().trim());
145 return null;
146 }
148 private String abbrev(Tree tree) {
149 int max = 48;
150 String s = tree.toString().replaceAll("[ \n]+", " ");
151 return (s.length() < max ? s : s.substring(0, max-3) + "...");
152 }
153 }
155 // prefix filenames with a directory
156 static Iterable<File> getFiles(File dir, String... names) {
157 List<File> files = new ArrayList<File>(names.length);
158 for (String name: names)
159 files.add(new File(dir, name));
160 return files;
161 }
163 static private <T> List<T> asList(Iterable<T> iter) {
164 List<T> l = new ArrayList<T>();
165 for (T t: iter)
166 l.add(t);
167 return l;
168 }
169 }