/* * Copyright (c) 1999, 2014, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ package com.sun.tools.javac.main; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; import java.util.Set; import java.util.stream.Stream; import java.util.stream.StreamSupport; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import com.sun.tools.doclint.DocLint; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.jvm.Profile; import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.main.OptionHelper.GrumpyHelper; import com.sun.tools.javac.platform.PlatformDescription; import com.sun.tools.javac.platform.PlatformProvider; import com.sun.tools.javac.platform.PlatformProvider.PlatformNotSupported; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Log.PrefixKind; import com.sun.tools.javac.util.Log.WriterKind; import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.PropagatedException; /** * Shared option and argument handling for command line and API usage of javac. */ public class Arguments { /** * The context key for the arguments. */ protected static final Context.Key argsKey = new Context.Key<>(); private String ownName; private Set classNames; private Set files; private Map deferredFileManagerOptions; private Set fileObjects; private final Options options; private JavaFileManager fileManager; private final Log log; private final Context context; private enum ErrorMode { ILLEGAL_ARGUMENT, ILLEGAL_STATE, LOG }; private ErrorMode errorMode; private boolean errors; /** * Gets the Arguments instance for this context. * * @param context the content * @return the Arguments instance for this context. */ public static Arguments instance(Context context) { Arguments instance = context.get(argsKey); if (instance == null) { instance = new Arguments(context); } return instance; } protected Arguments(Context context) { context.put(argsKey, this); options = Options.instance(context); log = Log.instance(context); this.context = context; // Ideally, we could init this here and update/configure it as // needed, but right now, initializing a file manager triggers // initialization of other items in the context, such as Lint // and FSInfo, which should not be initialized until after // processArgs // fileManager = context.get(JavaFileManager.class); } private final OptionHelper cmdLineHelper = new OptionHelper() { @Override public String get(Option option) { return options.get(option); } @Override public void put(String name, String value) { options.put(name, value); } @Override public void remove(String name) { options.remove(name); } @Override public boolean handleFileManagerOption(Option option, String value) { options.put(option.getText(), value); deferredFileManagerOptions.put(option, value); return true; } @Override public Log getLog() { return log; } @Override public String getOwnName() { return ownName; } @Override public void error(String key, Object... args) { Arguments.this.error(key, args); } @Override public void addFile(File f) { files.add(f); } @Override public void addClassName(String s) { classNames.add(s); } }; /** * Initializes this Args instance with a set of command line args. * The args will be processed in conjunction with the full set of * command line options, including -help, -version etc. * The args may also contain class names and filenames. * Any errors during this call, and later during validate, will be reported * to the log. * @param ownName the name of this tool; used to prefix messages * @param args the args to be processed */ public void init(String ownName, String... args) { this.ownName = ownName; errorMode = ErrorMode.LOG; files = new LinkedHashSet<>(); deferredFileManagerOptions = new LinkedHashMap<>(); fileObjects = null; classNames = new LinkedHashSet<>(); processArgs(List.from(args), Option.getJavaCompilerOptions(), cmdLineHelper, true, false); } private final OptionHelper apiHelper = new GrumpyHelper(null) { @Override public String get(Option option) { return options.get(option.getText()); } @Override public void put(String name, String value) { options.put(name, value); } @Override public void remove(String name) { options.remove(name); } @Override public void error(String key, Object... args) { Arguments.this.error(key, args); } @Override public Log getLog() { return Arguments.this.log; } }; /** * Initializes this Args instance with the parameters for a JavacTask. * The options will be processed in conjunction with the restricted set * of tool options, which does not include -help, -version, etc, * nor does it include classes and filenames, which should be specified * separately. * File manager options are handled directly by the file manager. * Any errors found while processing individual args will be reported * via IllegalArgumentException. * Any subsequent errors during validate will be reported via IllegalStateException. * @param ownName the name of this tool; used to prefix messages * @param options the options to be processed * @param classNames the classes to be subject to annotation processing * @param files the files to be compiled */ public void init(String ownName, Iterable options, Iterable classNames, Iterable files) { this.ownName = ownName; this.classNames = toSet(classNames); this.fileObjects = toSet(files); this.files = null; errorMode = ErrorMode.ILLEGAL_ARGUMENT; if (options != null) { processArgs(toList(options), Option.getJavacToolOptions(), apiHelper, false, true); } errorMode = ErrorMode.ILLEGAL_STATE; } /** * Gets the files to be compiled. * @return the files to be compiled */ public Set getFileObjects() { if (fileObjects == null) { if (files == null) { fileObjects = Collections.emptySet(); } else { fileObjects = new LinkedHashSet<>(); JavacFileManager jfm = (JavacFileManager) getFileManager(); for (JavaFileObject fo: jfm.getJavaFileObjectsFromFiles(files)) fileObjects.add(fo); } } return fileObjects; } /** * Gets the classes to be subject to annotation processing. * @return the classes to be subject to annotation processing */ public Set getClassNames() { return classNames; } /** * Processes strings containing options and operands. * @param args the strings to be processed * @param allowableOpts the set of option declarations that are applicable * @param helper a help for use by Option.process * @param allowOperands whether or not to check for files and classes * @param checkFileManager whether or not to check if the file manager can handle * options which are not recognized by any of allowableOpts * @return true if all the strings were successfully processed; false otherwise * @throws IllegalArgumentException if a problem occurs and errorMode is set to * ILLEGAL_ARGUMENT */ private boolean processArgs(Iterable args, Set