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