All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.tools.javac.main.Arguments Maven / Gradle / Ivy

There is a newer version: 21.0.0
Show newest version
/*
 * Copyright (c) 1999, 2019, 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.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import javax.lang.model.SourceVersion;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;

import com.sun.tools.doclint.DocLint;
import com.sun.tools.javac.code.Closeables;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Source.Feature;
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.PlatformUtils;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticInfo;
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;
import com.sun.tools.javac.util.StringUtils;
import java.io.Closeable;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * Shared option and argument handling for command line and API usage of javac.
 */
public class Arguments {

    /**
     * The context key for the arguments.
     */
    public static final Context.Key argsKey = new Context.Key<>();

    private String ownName;
    private Set classNames;
    private Set files;
    private Map deferredFileManagerOptions;
    private Set fileObjects;
    private boolean emptyAllowed;
    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, value);
            deferredFileManagerOptions.put(option, value);
            return true;
        }

        @Override
        public Log getLog() {
            return log;
        }

        @Override
        public String getOwnName() {
            return ownName;
        }

        @Override
        public void addFile(Path p) {
            files.add(p);
        }

        @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, Iterable args) {
        this.ownName = ownName;
        errorMode = ErrorMode.LOG;
        files = new LinkedHashSet<>();
        deferredFileManagerOptions = new LinkedHashMap<>();
        fileObjects = null;
        classNames = new LinkedHashSet<>();
        processArgs(args, Option.getJavaCompilerOptions(), cmdLineHelper, true, false);
        if (errors) {
            log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
        }
    }

    private final OptionHelper apiHelper = new GrumpyHelper(null) {
        @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 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;
    }

    /**
     * Minimal initialization for tools, like javadoc,
     * to be able to process javac options for themselves,
     * and then call validate.
     * @param ownName  the name of this tool; used to prefix messages
     */
    public void init(String ownName) {
        this.ownName = ownName;
        errorMode = ErrorMode.LOG;
    }

    /**
     * Gets the files to be compiled.
     * @return the files to be compiled
     */
    public Set getFileObjects() {
        if (fileObjects == null) {
            fileObjects = new LinkedHashSet<>();
        }
        if (files != null) {
            JavacFileManager jfm = (JavacFileManager) getFileManager();
            for (JavaFileObject fo: jfm.getJavaFileObjectsFromPaths(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;
    }

    /**
     * Handles the {@code --release} option.
     *
     * @param additionalOptions a predicate to handle additional options implied by the
     * {@code --release} option. The predicate should return true if all the additional
     * options were processed successfully.
     * @return true if successful, false otherwise
     */
    public boolean handleReleaseOptions(Predicate> additionalOptions) {
        String platformString = options.get(Option.RELEASE);

        checkOptionAllowed(platformString == null,
                option -> reportDiag(Errors.ReleaseBootclasspathConflict(option)),
                Option.BOOT_CLASS_PATH, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
                Option.XBOOTCLASSPATH_PREPEND,
                Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
                Option.EXTDIRS, Option.DJAVA_EXT_DIRS,
                Option.SOURCE, Option.TARGET,
                Option.SYSTEM, Option.UPGRADE_MODULE_PATH);

        if (platformString == null && !options.isSet(Option.BOOT_CLASS_PATH) &&
            !options.isSet(Option.XBOOTCLASSPATH) && !options.isSet(Option.SYSTEM) &&
            !options.isSet("ignore.symbol.file")) {
            Source source = Source.instance(context);
            Target target = Target.instance(context);
            setCtSymPaths(source, target);
        }
        if (platformString != null) {
            PlatformDescription platformDescription =
                    PlatformUtils.lookupPlatformDescription(platformString);

            if (platformDescription == null) {
                reportDiag(Errors.UnsupportedReleaseVersion(platformString));
                return false;
            }

            options.put(Option.SOURCE, platformDescription.getSourceVersion());
            options.put(Option.TARGET, platformDescription.getTargetVersion());

            context.put(PlatformDescription.class, platformDescription);

            if (!additionalOptions.test(platformDescription.getAdditionalOptions()))
                return false;

            JavaFileManager platformFM = platformDescription.getFileManager();
            DelegatingJavaFileManager.installReleaseFileManager(context,
                                                                platformFM,
                                                                getFileManager());
        }

        return true;
    }

        private void setCtSymPaths(Source s, Target t) {
            String ctSymVersion = targetNumericVersion(t);
            try {
                CtSymRoot ctSymRoot = ctSymRoot();
                Closeables closeablesService = Closeables.instance(context);
                closeablesService.closeables = closeablesService.closeables.prepend(ctSymRoot);
                Path root = ctSymRoot.root;
                StandardJavaFileManager fm = (StandardJavaFileManager) getFileManager();
                if (!Feature.MODULES.allowedInSource(s, t)) {
                    java.util.List paths = new ArrayList<>();

                    try (DirectoryStream dir = Files.newDirectoryStream(root)) {
                        for (Path section : dir) {
                            if (section.getFileName().toString().contains(ctSymVersion) &&
                                !section.getFileName().toString().contains("-")) {
                                try (DirectoryStream modules = Files.newDirectoryStream(section)) {
                                    for (Path module : modules) {
                                        paths.add(module);
                                    }
                                }
                            }
                        }
                    }

                    fm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, paths);
                } else {
                    Map> module2Paths = new HashMap<>();

                    try (DirectoryStream dir = Files.newDirectoryStream(root)) {
                        for (Path section : dir) {
                            if (section.getFileName().toString().contains(ctSymVersion) &&
                                !section.getFileName().toString().contains("-")) {
                                try (DirectoryStream modules = Files.newDirectoryStream(section)) {
                                    for (Path module : modules) {
                                        String moduleName = module.getFileName().toString();
                                        if (moduleName.endsWith("/"))
                                            moduleName = moduleName.substring(0, moduleName.length() - 1);
                                        module2Paths.computeIfAbsent(moduleName, dummy -> new ArrayList<>()).add(module);
                                    }
                                }
                            }
                        }
                    }

                    fm.handleOption("--system", Arrays.asList("none").iterator());

                    for (Map.Entry> e : module2Paths.entrySet()) {
                        fm.setLocationForModule(StandardLocation.SYSTEM_MODULES,
                                                e.getKey(),
                                                e.getValue());
                    }
                }
            } catch (IOException | URISyntaxException ex) {
                throw new IllegalStateException(ex);
            }
        }

        private static String targetNumericVersion(Target target) {
            return StringUtils.toUpperCase(Integer.toString(target.ordinal() - Target.JDK1_1.ordinal() + 1, Character.MAX_RADIX));
        }

    public static CtSymRoot ctSymRoot() throws IOException, URISyntaxException {
        CodeSource cs = Arguments.class.getProtectionDomain().getCodeSource();
        URL location = cs != null ? cs.getLocation() : null;
        if (location == null) {
            throw new IllegalStateException("Cannot find ct.sym data!");
        }
        Path locationPath = Paths.get(location.toURI());
        boolean isJar = Files.isRegularFile(locationPath);
        Path root;
        Closeable closeable;
        if (isJar) {
            FileSystem jar = FileSystems.newFileSystem(locationPath, (ClassLoader) null);
            root = jar.getPath("META-INF", "ct.sym");
            closeable = jar;
        } else {
            root = locationPath.resolve("META-INF").resolve("ct.sym");
            closeable = null;
        }
        return new CtSymRoot(root, closeable);
    }

    public static final class CtSymRoot implements Closeable {
        public final Path root;
        private final Closeable delegateCloseable;

        public CtSymRoot(Path root, Closeable delegateCloseable) {
            this.root = root;
            this.delegateCloseable = delegateCloseable;
        }

        @Override
        public void close() throws IOException {
            if (delegateCloseable != null) {
                delegateCloseable.close();
            }
        }

    }

    /**
     * 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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy