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

framework.src.org.checkerframework.framework.util.PluginUtil Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.framework.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This file contains basic utility functions that should be reused to create
 * a command line call to CheckerMain.
 *
 * NOTE: There are multiple copies of this file in the following projects/locations:
 * maven-plugin/
 *     org.checkerframework.mavenplugin.PluginUtil
 *
 * checker-framework-eclipse-plugin/
 *     org.checkerframework.eclipse.util.PluginUtil
 *
 * checker-framework/
 *     org.checkerframework.framework.util.PluginUtil
 *
 * These files MUST be IDENTICAL after the package descriptor.
 */
public class PluginUtil {

    /**
     * Option name for specifying an alternative javac.jar location.  The accompanying value
     * MUST be the path to the jar file (NOT the path to its encompassing directory)
     */
    public static final String JAVAC_PATH_OPT = "-javacJar";

    /**
     * Option name for specifying an alternative jdk.jar location.  The accompanying value
     * MUST be the path to the jar file (NOT the path to its encompassing directory)
     */
    public static final String JDK_PATH_OPT   = "-jdkJar";


    public static List toFiles(final List fileNames) {
        final List files = new ArrayList(fileNames.size());
        for (final String fn : fileNames) {
            files.add(new File(fn));
        }

        return files;
    }

    /**
     * Takes a list of files and writes it as a "File of file names" (i.e. a file with one filepath on each line)
     * to the destination file, overwriting the destination file if it exists.  Note the filepath used is the
     * absolute filepath
     * @param destination the fofn file we are writing.  This file will contain newline separated list of absolute file paths
     * @param files the files to write to the destination file
     */
    public static void writeFofn(final File destination, final List files) throws IOException {
        final BufferedWriter bw = new BufferedWriter(new FileWriter(destination));
        try {
            for (final File file : files) {
                bw.write(wrapArg(file.getAbsolutePath()));
                bw.newLine();
            }

            bw.flush();
        } finally {
            bw.close();
        }
    }

    /**
     * Takes a list of files and writes it as a "File of file names" (i.e. a file with one filepath on each line)
     * to the destination file, overwriting the destination file if it exists.  Note the filepath used is the
     * absolute filepath
     * @param destination the fofn file we are writing.  This file will contain newline separated list of absolute file paths
     * @param files the files to write to the destination file
     */
    public static void writeFofn(final File destination, final File ... files) throws IOException {
        writeFofn(destination, Arrays.asList(files));
    }

    public static File writeTmpFofn(final String prefix, final String suffix, final boolean deleteOnExit,
                                    final List files) throws IOException {
        final File tmpFile = File.createTempFile(prefix, suffix);
        if (deleteOnExit) {
            tmpFile.deleteOnExit();
        }
        writeFofn(tmpFile, files);
        return tmpFile;
    }

    /**
     * Write the strings to a temporary file.
     * @param deleteOnExit if true, delete the file on program exit
     */
    public static File writeTmpFile(final String prefix, final String suffix, final boolean deleteOnExit,
                                       final List args) throws IOException {
        final File tmpFile = File.createTempFile(prefix, suffix);
        if (deleteOnExit) {
            tmpFile.deleteOnExit();
        }
        writeFile(tmpFile, args);
        return tmpFile;
    }

    /** Write the strings to the file, one per line. */
    public static void writeFile(final File destination, final List contents) throws IOException {
        final BufferedWriter bw = new BufferedWriter(new FileWriter(destination));
        try {
            for (String line : contents) {
                bw.write(line);
                bw.newLine();
            }
            bw.flush();
        } finally {
            bw.close();
        }
    }


    /** Return a list of Strings, one per line of the file. */
    public static List readFile(final File argFile) throws IOException {
        final BufferedReader br = new BufferedReader(new FileReader(argFile));
        String line;

        List lines = new ArrayList();
        while ((line = br.readLine()) != null) {
            lines.add(line);
        }
        br.close();
        return lines;
    }

    public static  String join(final String delimiter, final T[] objs) {

        boolean notFirst = false;
        final StringBuffer sb = new StringBuffer();

        for (final Object obj : objs) {
            if (notFirst) {
                sb.append(delimiter);
            }
            sb.append(obj.toString());
            notFirst = true;
        }

        return sb.toString();
    }

    public static String join(String delimiter, Iterable values) {
        StringBuilder sb = new StringBuilder();

        boolean isntFirst = false;
        for (Object value : values) {
            if (isntFirst) {
                sb.append(delimiter);
            }
            sb.append(value);
            isntFirst = true;
        }

        return sb.toString();
    }


    public static List getStringProp(final Map props,
                                             final CheckerProp prop, final String tag,
                                             final String ... extras) {
        final List out = new ArrayList();
        final String strProp = (String) props.get(prop);
        if (strProp != null && !strProp.isEmpty()) {
            out.add(tag + strProp);
            for (final String extra : extras) {
                out.add(extra);
            }
        }

        return out;
    }

    public static List getBooleanProp(final Map props,
                                              final CheckerProp prop, final String tag) {
        Boolean aSkip = (Boolean) props.get(prop);
        if (aSkip != null && aSkip) {
            return Arrays.asList(tag);
        }
        return new ArrayList();
    }

    public enum CheckerProp {
        IMPLICIT_IMPORTS() {
            @Override
            public List getCmdLine(final Map props) {
                return getStringProp(props, this, "-J-Djsr308_imports=", "-implicit:class");
            }
        },

        MISC_COMPILER() {
            @Override
            public List getCmdLine(final Map props) {
                @SuppressWarnings("unchecked")
                List miscOpts = (List) props.get(this);

                if (miscOpts != null && !miscOpts.isEmpty()) {
                    return new ArrayList(miscOpts);
                }
                return new ArrayList();
            }
        },

        A_SKIP() {
            @Override
            public List getCmdLine(final Map props) {
                return getStringProp(props, this, "-AskipUses=");
            }
        },

        A_LINT() {
            @Override
            public List getCmdLine(final Map props) {
                return getStringProp(props, this, "-Alint=");
            }
        },

        A_WARNS() {
            @Override
            public List getCmdLine(final Map props) {
                return getBooleanProp(props, this, "-Awarns");
            }
        },
        A_NO_MSG_TXT() {
            @Override
            public List getCmdLine(final Map props) {
                return getBooleanProp(props, this, "-Anomsgtext");
            }
        },
        A_SHOW_CHECKS() {
            @Override
            public List getCmdLine(final Map props) {
                return getBooleanProp(props, this, "-Ashowchecks");
            }
        },
        A_FILENAMES() {
            @Override
            public List getCmdLine(final Map props) {
                return getBooleanProp(props, this, "-Afilenames");
            }
        },
        A_DETAILED_MSG() {
            @Override
            public List getCmdLine(final Map props) {
                return getBooleanProp(props, this, "-Adetailedmsgtext");
            }
        };

        public abstract List getCmdLine(final Map props);

    }

    /**
     * Any options found in props to the cmd list
     * @param cmd    a list to which the options should be added
     * @param props  the map of checker properties too search for options in
     */
    private static void addOptions(final List cmd, Map props) {
        for (CheckerProp cp : CheckerProp.values()) {
            cmd.addAll(cp.getCmdLine(props));
        }
    }

    public static File writeTmpSrcFofn(final String prefix, final boolean deleteOnExit,
                                       final List files) throws IOException {
        return writeTmpFofn(prefix, ".src_files", deleteOnExit, files);
    }

    public static File writeTmpCpFile(final String prefix, final boolean deleteOnExit,
                                      final String classpath) throws IOException {
        return writeTmpFile(prefix, ".classpath", deleteOnExit, Arrays.asList("-classpath", wrapArg(classpath)));
    }

    public static boolean isWindows() {
        final String os = System.getProperty("os.name");
        return os.toLowerCase().contains("win");
    }

    public static String wrapArg(final String classpath) {
        if (classpath.contains(" ")) {
            return '"' + escapeQuotesAndSlashes(classpath) + '"';
        }
        return classpath;
    }

    public static String escapeQuotesAndSlashes(final String toEscape) {
        final Map replacements = new HashMap();
        replacements.put("\\\\", "\\\\\\\\");
        replacements.put("\"", "\\\\\"");

        String replacement = toEscape;
        for (final Map.Entry entry : replacements.entrySet()) {
            replacement = replacement.replaceAll(entry.getKey(), entry.getValue());
        }

        return replacement;
    }

    public static String getJavaCommand(final String javaHome, final PrintStream out) {
        if (javaHome == null || javaHome.equals("")) {
            return "java";
        }

        final File java    = new File(javaHome, "bin" + File.separator + "java");
        final File javaExe = new File(javaHome, "bin" + File.separator + "java.exe");
        if (java.exists()) {
            return java.getAbsolutePath();
        } else if (javaExe.exists()) {
            return javaExe.getAbsolutePath();
        } else {
            if (out != null) {
                out.println("Could not find java executable at: ( " + java.getAbsolutePath()    + "," +
                        javaExe.getAbsolutePath() + ")" +
                        "\n  Using \"java\" command.\n");
            }
            return "java";
        }
    }

    public static String fileArgToStr(final File fileArg) {
        return "@" + fileArg.getAbsolutePath();
    }


    //TODO: Perhaps unify this with CheckerMain as it violates DRY
    public static List getCmd(final String executable,  final File javacPath, final File jdkPath,
                                      final File srcFofn, final String processors,
                                      final String checkerHome, final String javaHome,
                                      final File classPathFofn, final String bootClassPath,
                                      final Map props, PrintStream out,
                                      final boolean procOnly, final String outputDirectory) {

        final List cmd = new ArrayList();

        final String java    = ( executable != null ) ? executable
                : getJavaCommand(javaHome, out);

        cmd.add(java);
        cmd.add("-jar");
        cmd.add(checkerHome);

        if (procOnly) {
            cmd.add("-proc:only");
        } else if (outputDirectory != null) {
            cmd.add("-d");
            cmd.add(outputDirectory);
        }

        if (bootClassPath != null && !bootClassPath.trim().isEmpty()) {
            cmd.add("-Xbootclasspath/p:" +  bootClassPath);
        }

        if (javacPath != null) {
            cmd.add(JAVAC_PATH_OPT);
            cmd.add(javacPath.getAbsolutePath());
        }

        if (jdkPath != null) {
            cmd.add(JDK_PATH_OPT);
            cmd.add(jdkPath.getAbsolutePath());
        }

        if (classPathFofn != null ) {
            cmd.add(fileArgToStr(classPathFofn));
        }

        if (processors != null) {
            cmd.add("-processor");
            cmd.add(processors);
        }

        addOptions(cmd, props);
        cmd.add(fileArgToStr(srcFofn));

        return cmd;

    }

    public static List toJavaOpts(final List opts) {
        final List outOpts = new ArrayList(opts.size());
        for (final String opt : opts) {
            outOpts.add("-J" + opt);
        }

        return outOpts;
    }

    public static List getCmdArgsOnly(final File srcFofn, final String processors,
                                              final String checkerHome, final String javaHome,
                                              final File classpathFofn,   final String bootClassPath,
                                              final Map props, PrintStream out,
                                              final boolean procOnly, final String outputDirectory) {

        final List cmd = getCmd(null, null, null, srcFofn, processors,
                checkerHome, javaHome, classpathFofn, bootClassPath, props, out,
                procOnly, outputDirectory);
        cmd.remove(0);
        return cmd;
    }



    public static List getCmdArgsOnly(final File javacPath, final File jdkPath,
                                              final File srcFofn, final String processors,
                                              final String checkerHome, final String javaHome,
                                              final File classpathFofn,   final String bootClassPath,
                                              final Map props, PrintStream out,
                                              final boolean procOnly, final String outputDirectory) {

        final List cmd = getCmd(null, javacPath, jdkPath, srcFofn, processors,
                checkerHome, javaHome, classpathFofn, bootClassPath, props, out,
                procOnly, outputDirectory);
        cmd.remove(0);
        return cmd;
    }

    /**
     * Extract the first two version numbers from java.version (e.g. 1.6 from 1.6.whatever)
     * @return the first two version numbers from java.version (e.g. 1.6 from 1.6.whatever)
     */
    public static double getJreVersion() {
        final Pattern versionPattern = Pattern.compile("^(\\d\\.\\d+)\\..*$");
        final String  jreVersionStr = System.getProperty("java.version");
        final Matcher versionMatcher = versionPattern.matcher(jreVersionStr);

        final double version;
        if (versionMatcher.matches()) {
            version = Double.parseDouble(versionMatcher.group(1));
        } else {
            throw new RuntimeException("Could not determine version from property java.version=" + jreVersionStr);
        }

        return version;
    }

    /**
     * Determine the version of the JRE that we are currently running and select a jdkX where
     * X is the version of Java that is being run (e.g. 6, 7, ...)
     * @return the jdkX where X is the version of Java that is being run (e.g. 6, 7, ...)
     */
    public static String getJdkJarPrefix() {
        final double jreVersion = getJreVersion();
        final String prefix;
        if (jreVersion == 1.4 || jreVersion == 1.5 || jreVersion == 1.6) {
            // TODO: raise an error, these versions are no longer supported.
            prefix = "jdk6";
        } else if (jreVersion == 1.7) {
            prefix = "jdk7";
        } else if (jreVersion == 1.8) {
            prefix = "jdk8";
        } else if (jreVersion == 1.9) {
            prefix = "jdk9";
        } else {
            throw new AssertionError("Unsupported JRE version: " + jreVersion);
        }

        return prefix;
    }

    /**
     * Determine the version of the JRE that we are currently running and select a jdkX.jar where
     * X is the version of Java that is being run (e.g. 6, 7, ...)
     * @return the jdkX.jar where X is the version of Java that is being run (e.g. 6, 7, ...)
     */
    public static String getJdkJarName() {
        final String fileName = getJdkJarPrefix() + ".jar";
        return fileName;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy