Checker.java revision 553:9d9f26857129
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 */ 23 24import java.io.*; 25import java.util.*; 26import javax.lang.model.util.*; 27import javax.tools.*; 28import com.sun.tools.javac.api.*; 29import com.sun.source.tree.*; 30import com.sun.source.util.*; 31import com.sun.tools.javac.tree.JCTree; 32import com.sun.tools.javac.tree.JCTree.*; 33import com.sun.tools.javac.util.Position; 34 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 */ 42abstract 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")); 46 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 }; 55 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(); 62 63 if (errors) 64 throw new AssertionError("errors occurred creating trees"); 65 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; 72 73 if (errors) 74 throw new AssertionError("errors occurred checking scopes"); 75 } 76 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; 83 84 if (s == null) { 85 error(s, ref, "scope missing"); 86 return false; 87 } 88 89 if (ref == null) { 90 error(s, ref, "scope unexpected"); 91 return false; 92 } 93 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 } 104 105 return checkLocal(s, local.trim()) 106 & check(s.getEnclosingScope(), encl); 107 } 108 109 // override if using default check(Scope,String) 110 boolean checkLocal(Scope s, String ref) { 111 throw new IllegalStateException(); 112 } 113 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 } 121 122 protected Elements getElements() { 123 return task.getElements(); 124 } 125 126 protected Trees getTrees() { 127 return Trees.instance(task); 128 } 129 130 boolean errors = false; 131 protected JavacTask task; 132 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 } 147 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 } 154 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 } 162 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} 170