Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/make/tools/genstubs/GenStubs.java
32285 views
/*1* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package genstubs;2627import java.io.*;28import java.util.*;29import javax.tools.JavaFileObject;30import javax.tools.StandardJavaFileManager;31import javax.tools.StandardLocation;3233import com.sun.source.tree.CompilationUnitTree;34import com.sun.source.util.JavacTask;35import com.sun.tools.javac.api.JavacTool;36import com.sun.tools.javac.code.Flags;37import com.sun.tools.javac.code.TypeTag;38import com.sun.tools.javac.tree.JCTree;39import com.sun.tools.javac.tree.JCTree.JCClassDecl;40import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;41import com.sun.tools.javac.tree.JCTree.JCFieldAccess;42import com.sun.tools.javac.tree.JCTree.JCIdent;43import com.sun.tools.javac.tree.JCTree.JCImport;44import com.sun.tools.javac.tree.JCTree.JCLiteral;45import com.sun.tools.javac.tree.JCTree.JCMethodDecl;46import com.sun.tools.javac.tree.JCTree.JCModifiers;47import com.sun.tools.javac.tree.JCTree.JCVariableDecl;48import com.sun.tools.javac.tree.Pretty;49import com.sun.tools.javac.tree.TreeMaker;50import com.sun.tools.javac.tree.TreeScanner;51import com.sun.tools.javac.tree.TreeTranslator;52import com.sun.tools.javac.util.Context;53import com.sun.tools.javac.util.ListBuffer;54import com.sun.tools.javac.util.Name;55import javax.tools.JavaFileManager;5657/**58* Generate stub source files by removing implementation details from input files.59*60* This is a special purpose stub generator, specific to the needs of generating61* stub files for JDK 7 API that are needed to compile langtools files that depend62* on that API. The stub generator works by removing as much of the API source code63* as possible without affecting the public signature, in order to reduce the64* transitive closure of the API being referenced. The resulting stubs can be65* put on the langtools sourcepath with -implicit:none to compile the langtools66* files that depend on the JDK 7 API.67*68* Usage:69* genstubs -s <outdir> -sourcepath <path> <classnames>70*71* The specified class names are looked up on the sourcepath, and corresponding72* stubs are written to the source output directory.73*74* Classes are parsed into javac ASTs, then processed with a javac TreeTranslator75* to remove implementation details, and written out in the source output directory.76* Documentation comments and annotations are removed. Method bodies are removed77* and methods are marked native. Private and package-private field definitions78* have their initializers replace with 0, 0.0, false, null as appropriate.79*/8081public class GenStubs {82static class Fault extends Exception {83private static final long serialVersionUID = 0;84Fault(String message) {85super(message);86}87Fault(String message, Throwable cause) {88super(message);89initCause(cause);90}91}9293public static void main(String[] args) {94boolean ok = new GenStubs().run(args);95if (!ok)96System.exit(1);97}9899public boolean run(String... args) {100File outdir = null;101String sourcepath = null;102List<String> classes = new ArrayList<String>();103for (ListIterator<String> iter = Arrays.asList(args).listIterator(); iter.hasNext(); ) {104String arg = iter.next();105if (arg.equals("-s") && iter.hasNext())106outdir = new File(iter.next());107else if (arg.equals("-sourcepath") && iter.hasNext())108sourcepath = iter.next();109else if (arg.startsWith("-"))110throw new IllegalArgumentException(arg);111else {112classes.add(arg);113while (iter.hasNext())114classes.add(iter.next());115}116}117118return run(sourcepath, outdir, classes);119}120121public boolean run(String sourcepath, File outdir, List<String> classes) {122//System.err.println("run: sourcepath:" + sourcepath + " outdir:" + outdir + " classes:" + classes);123if (sourcepath == null)124throw new IllegalArgumentException("sourcepath not set");125if (outdir == null)126throw new IllegalArgumentException("source output dir not set");127128JavacTool tool = JavacTool.create();129StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);130131try {132fm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outdir));133fm.setLocation(StandardLocation.SOURCE_PATH, splitPath(sourcepath));134List<JavaFileObject> files = new ArrayList<JavaFileObject>();135for (String c: classes) {136JavaFileObject fo = fm.getJavaFileForInput(137StandardLocation.SOURCE_PATH, c, JavaFileObject.Kind.SOURCE);138if (fo == null)139error("class not found: " + c);140else141files.add(fo);142}143144JavacTask t = tool.getTask(null, fm, null, null, null, files);145Iterable<? extends CompilationUnitTree> trees = t.parse();146for (CompilationUnitTree tree: trees) {147makeStub(fm, tree);148}149} catch (IOException e) {150error("IO error " + e, e);151}152153return (errors == 0);154}155156void makeStub(StandardJavaFileManager fm, CompilationUnitTree tree) throws IOException {157CompilationUnitTree tree2 = new StubMaker().translate(tree);158CompilationUnitTree tree3 = new ImportCleaner(fm).removeRedundantImports(tree2);159160String className = fm.inferBinaryName(StandardLocation.SOURCE_PATH, tree.getSourceFile());161JavaFileObject fo = fm.getJavaFileForOutput(StandardLocation.SOURCE_OUTPUT,162className, JavaFileObject.Kind.SOURCE, null);163// System.err.println("Writing " + className + " to " + fo.getName());164Writer out = fo.openWriter();165try {166new Pretty(out, true).printExpr((JCTree) tree3);167} finally {168out.close();169}170}171172List<File> splitPath(String path) {173List<File> list = new ArrayList<File>();174for (String p: path.split(File.pathSeparator)) {175if (p.length() > 0)176list.add(new File(p));177}178return list;179}180181void error(String message) {182System.err.println(message);183errors++;184}185186void error(String message, Throwable cause) {187error(message);188}189190int errors;191192class StubMaker extends TreeTranslator {193CompilationUnitTree translate(CompilationUnitTree tree) {194return super.translate((JCCompilationUnit) tree);195}196197/**198* compilation units: remove javadoc comments199* -- required, in order to remove @deprecated tags, since we200* (separately) remove all annotations, including @Deprecated201*/202public void visitTopLevel(JCCompilationUnit tree) {203super.visitTopLevel(tree);204tree.docComments = null;205}206207/**208* methods: remove method bodies, make methods native209*/210@Override211public void visitClassDef(JCClassDecl tree) {212long prevClassMods = currClassMods;213currClassMods = tree.mods.flags;214try {215super.visitClassDef(tree);;216} finally {217currClassMods = prevClassMods;218}219}220private long currClassMods = 0;221222/**223* methods: remove method bodies, make methods native224*/225@Override226public void visitMethodDef(JCMethodDecl tree) {227tree.mods = translate(tree.mods);228tree.restype = translate(tree.restype);229tree.typarams = translateTypeParams(tree.typarams);230tree.params = translateVarDefs(tree.params);231tree.thrown = translate(tree.thrown);232if (tree.body != null) {233if ((currClassMods & Flags.INTERFACE) != 0) {234tree.mods.flags &= ~(Flags.DEFAULT | Flags.STATIC);235} else {236tree.mods.flags |= Flags.NATIVE;237}238tree.body = null;239}240result = tree;241}242243/**244* modifiers: remove annotations245*/246@Override247public void visitModifiers(JCModifiers tree) {248tree.annotations = com.sun.tools.javac.util.List.nil();249result = tree;250}251252/**253* field definitions: replace initializers with 0, 0.0, false etc254* when possible -- i.e. leave public, protected initializers alone255*/256@Override257public void visitVarDef(JCVariableDecl tree) {258tree.mods = translate(tree.mods);259tree.vartype = translate(tree.vartype);260if (tree.init != null) {261if ((tree.mods.flags & (Flags.PUBLIC | Flags.PROTECTED)) != 0)262tree.init = translate(tree.init);263else {264String t = tree.vartype.toString();265if (t.equals("boolean"))266tree.init = new JCLiteral(TypeTag.BOOLEAN, 0) { };267else if (t.equals("byte"))268tree.init = new JCLiteral(TypeTag.BYTE, 0) { };269else if (t.equals("char"))270tree.init = new JCLiteral(TypeTag.CHAR, 0) { };271else if (t.equals("double"))272tree.init = new JCLiteral(TypeTag.DOUBLE, 0.d) { };273else if (t.equals("float"))274tree.init = new JCLiteral(TypeTag.FLOAT, 0.f) { };275else if (t.equals("int"))276tree.init = new JCLiteral(TypeTag.INT, 0) { };277else if (t.equals("long"))278tree.init = new JCLiteral(TypeTag.LONG, 0) { };279else if (t.equals("short"))280tree.init = new JCLiteral(TypeTag.SHORT, 0) { };281else282tree.init = new JCLiteral(TypeTag.BOT, null) { };283}284}285result = tree;286}287}288289class ImportCleaner extends TreeScanner {290private Set<Name> names = new HashSet<Name>();291private TreeMaker m;292293ImportCleaner(JavaFileManager fm) {294// ImportCleaner itself doesn't require a filemanager, but instantiating295// a TreeMaker does, indirectly (via ClassReader, sigh)296Context c = new Context();297c.put(JavaFileManager.class, fm);298m = TreeMaker.instance(c);299}300301CompilationUnitTree removeRedundantImports(CompilationUnitTree t) {302JCCompilationUnit tree = (JCCompilationUnit) t;303tree.accept(this);304ListBuffer<JCTree> defs = new ListBuffer<JCTree>();305for (JCTree def: tree.defs) {306if (def.getTag() == JCTree.Tag.IMPORT) {307JCImport imp = (JCImport) def;308if (imp.qualid.getTag() == JCTree.Tag.SELECT) {309JCFieldAccess qualid = (JCFieldAccess) imp.qualid;310if (!qualid.name.toString().equals("*")311&& !names.contains(qualid.name)) {312continue;313}314}315}316defs.add(def);317}318return m.TopLevel(tree.packageAnnotations, tree.pid, defs.toList());319}320321@Override322public void visitImport(JCImport tree) { } // ignore names found in imports323324@Override325public void visitIdent(JCIdent tree) {326names.add(tree.name);327}328329@Override330public void visitSelect(JCFieldAccess tree) {331super.visitSelect(tree);332names.add(tree.name);333}334}335}336337338