Package com.google.errorprone.intellij

Source Code of com.google.errorprone.intellij.ErrorProneIdeaCompiler$MyException

package com.google.errorprone.intellij;

import com.google.errorprone.matchers.Matcher;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.javaCompiler.ExternalCompiler;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
import com.intellij.compiler.impl.javaCompiler.javac.JavacConfigurable;
import com.intellij.compiler.impl.javaCompiler.javac.JavacConfiguration;
import com.intellij.compiler.impl.javaCompiler.javac.JavacOutputParser;
import com.intellij.compiler.impl.javaCompiler.javac.JavacSettingsBuilder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerPaths;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.impl.MockJdkWrapper;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.java.compiler.AnnotationProcessingConfiguration;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class ErrorProneIdeaCompiler extends ExternalCompiler {

  private final Project myProject;
  private final List<File> myTempFiles = new ArrayList<File>();
  @NonNls
  private boolean myAnnotationProcessorMode = false;

  public ErrorProneIdeaCompiler(Project project) {
    myProject = project;
  }

  public boolean checkCompiler(final CompileScope scope) {
    final Module[] modules = scope.getAffectedModules();
    final Set<Sdk> checkedJdks = new HashSet<Sdk>();
    for (final Module module : modules) {
      final Sdk jdk = ModuleRootManager.getInstance(module).getSdk();
      if (jdk == null || checkedJdks.contains(jdk)) {
        continue;
      }
      checkedJdks.add(jdk);
      final SdkTypeId sdkType = jdk.getSdkType();
      if (!(sdkType instanceof JavaSdkType)) {
        continue;
      }
      final VirtualFile homeDirectory = jdk.getHomeDirectory();
      if (homeDirectory == null) {
        //noinspection DialogTitleCapitalization
        Messages.showMessageDialog(
            myProject,
            ErrorProneIdeaBundle.jdkHomeNotFoundMessage(jdk),
            ErrorProneIdeaBundle.compilerName(),
            Messages.getErrorIcon()
        );
        return false;
      }
      final String vmExecutablePath = ((JavaSdkType)sdkType).getVMExecutablePath(jdk);
      if (vmExecutablePath == null) {
        Messages.showMessageDialog(
            myProject,
            ErrorProneIdeaBundle.message("error-prone.error.vm.executable.missing", jdk.getName()),
            ErrorProneIdeaBundle.compilerName(),
            Messages.getErrorIcon()
        );
        return false;
      }
      final String toolsJarPath = ((JavaSdkType)sdkType).getToolsPath(jdk);
      if (toolsJarPath == null) {
        Messages.showMessageDialog(
            myProject,
            ErrorProneIdeaBundle.message("error-prone.error.tools.jar.missing", jdk.getName()),
            ErrorProneIdeaBundle.compilerName(),
            Messages.getErrorIcon()
        );
        return false;
      }
      final String versionString = jdk.getVersionString();
      if (versionString == null) {
        Messages.showMessageDialog(
            myProject,
            ErrorProneIdeaBundle.message("error-prone.error.unknown.jdk.version", jdk.getName()),
            ErrorProneIdeaBundle.compilerName(),
            Messages.getErrorIcon()
        );
        return false;
      }

      if (CompilerUtil.isOfVersion(versionString, "1.0")) {
        Messages.showMessageDialog(
            myProject,
            ErrorProneIdeaBundle.message("error-prone.error.1_0_compilation.not.supported"),
            ErrorProneIdeaBundle.compilerName(),
            Messages.getErrorIcon()
        );
        return false;
      }
    }

    return true;
  }

  @NotNull
  @NonNls
  public String getId() { // used for externalization
    return "Javac (with error-prone)";
  }

  @NotNull
  public String getPresentableName() {
    return ErrorProneIdeaBundle.compilerName();
  }

  @NotNull
  public Configurable createConfigurable() {
    return new JavacConfigurable(JavacConfiguration.getOptions(myProject, JavacConfiguration.class));
  }

  public OutputParser createErrorParser(@NotNull final String outputDir, Process process) {
    return new JavacOutputParser(myProject);
  }

  public OutputParser createOutputParser(@NotNull final String outputDir) {
    return null;
  }

  private static class MyException extends RuntimeException {
    private MyException(Throwable cause) {
      super(cause);
    }
  }

  @NotNull
  public String[] createStartupCommand(final ModuleChunk chunk, final CompileContext context, final String outputPath)
      throws IOException, IllegalArgumentException {

    try {
      return ApplicationManager.getApplication().runReadAction(new Computable<String[]>() {
        public String[] compute() {
          try {
            final List<String> commandLine = new ArrayList<String>();
            createStartupCommand(chunk, commandLine, outputPath, JavacConfiguration.getOptions(myProject, JavacConfiguration.class), context.isAnnotationProcessorsEnabled());
            System.out.println("Called as \n  " + StringUtil.join(commandLine, " "));
            return ArrayUtil.toStringArray(commandLine);
          }
          catch (IOException e) {
            throw new MyException(e);
          }
        }
      });
    }
    catch (MyException e) {
      Throwable cause = e.getCause();
      if (cause instanceof IOException) {
        throw (IOException)cause;
      }
      throw e;
    }
  }

  private void createStartupCommand(final ModuleChunk chunk, @NonNls final List<String> commandLine, final String outputPath,
                                    JpsJavaCompilerOptions javacOptions, final boolean annotationProcessorsEnabled) throws IOException {
    final Sdk jdk = getJdkForStartupCommand(chunk);
    final String versionString = jdk.getVersionString();
    JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk);
    if (versionString == null || version == null || !(jdk.getSdkType() instanceof JavaSdkType)) {
      throw new IllegalArgumentException(CompilerBundle.message("javac.error.unknown.jdk.version", jdk.getName()));
    }

    JavaSdkType sdkType = (JavaSdkType)jdk.getSdkType();

    final String toolsJarPath = sdkType.getToolsPath(jdk);
    if (toolsJarPath == null) {
      throw new IllegalArgumentException(CompilerBundle.message("javac.error.tools.jar.missing", jdk.getName()));
    }

    final String vmExePath = sdkType.getVMExecutablePath(jdk);

    commandLine.add(vmExePath);

    commandLine.add("-Xmx" + javacOptions.MAXIMUM_HEAP_SIZE + "m");

    final List<String> additionalOptions =
      addAdditionalSettings(commandLine, javacOptions, myAnnotationProcessorMode, version, chunk, annotationProcessorsEnabled);

    CompilerUtil.addLocaleOptions(commandLine, false);

    commandLine.add("-classpath");

    commandLine.add(sdkType.getToolsPath(jdk) + File.pathSeparator + PathUtil.getJarPathForClass(Matcher.class));

    commandLine.add("com.google.errorprone.ErrorProneCompiler");

    addCommandLineOptions(chunk, commandLine, outputPath, jdk, myAnnotationProcessorMode);

    commandLine.addAll(additionalOptions);

    final List<VirtualFile> files = chunk.getFilesToCompile();

    for (final VirtualFile file : files) {
      commandLine.add(file.getPath());
    }
  }

  public static List<String> addAdditionalSettings(List<String> commandLine, JpsJavaCompilerOptions javacOptions, boolean isAnnotationProcessing,
                                                   JavaSdkVersion version, ModuleChunk chunk, boolean annotationProcessorsEnabled) {
    final List<String> additionalOptions = new ArrayList<String>();
      StringTokenizer tokenizer = new StringTokenizer(new JavacSettingsBuilder(javacOptions).getOptionsString(chunk), " ");
    if (isAnnotationProcessing) {
      final AnnotationProcessingConfiguration config = CompilerConfiguration.getInstance(chunk.getProject()).getAnnotationProcessingConfiguration(chunk.getModules()[0]);
      additionalOptions.add("-Xprefer:source");
      additionalOptions.add("-implicit:none");
      additionalOptions.add("-proc:only");
      if (!config.isObtainProcessorsFromClasspath()) {
        final String processorPath = config.getProcessorPath();
        additionalOptions.add("-processorpath");
        additionalOptions.add(FileUtil.toSystemDependentName(processorPath));
      }
      final Set<String> processors = config.getProcessors();
      if (!processors.isEmpty()) {
        additionalOptions.add("-processor");
        additionalOptions.add(StringUtil.join(processors, ","));
      }
      for (Map.Entry<String, String> entry : config.getProcessorOptions().entrySet()) {
        additionalOptions.add("-A" + entry.getKey() + "=" +entry.getValue());
      }
    }
    else {
      if (annotationProcessorsEnabled) {
        // Unless explicitly specified by user, disable annotation processing by default for 'java compilation' mode
        // This is needed to suppress unwanted side-effects from auto-discovered processors from compilation classpath
        additionalOptions.add("-proc:none");
      }
    }

    while (tokenizer.hasMoreTokens()) {
      @NonNls String token = tokenizer.nextToken();
      if (version == JavaSdkVersion.JDK_1_0 && "-deprecation".equals(token)) {
        continue; // not supported for this version
      }
      if (!version.isAtLeast(JavaSdkVersion.JDK_1_5) && "-Xlint".equals(token)) {
        continue; // not supported in these versions
      }
      if (isAnnotationProcessing) {
        if (token.startsWith("-proc:")) {
          continue;
        }
        if (token.startsWith("-implicit:")) {
          continue;
        }
      }
      else { // compiling java
        if (annotationProcessorsEnabled) {
          // in this mode we have -proc:none already added above, so user's settings should be ignored
          if (token.startsWith("-proc:")) {
            continue;
          }
        }
      }
      if (token.startsWith("-J-")) {
        commandLine.add(token.substring("-J".length()));
      }
      else {
        additionalOptions.add(token);
      }
    }

    return additionalOptions;
  }

  public static void addCommandLineOptions(@NotNull ModuleChunk chunk,
                                           @NonNls List<String> commandLine,
                                           @NotNull String outputPath,
                                           @NotNull Sdk jdk,
                                           boolean isAnnotationProcessingMode) throws IOException {

    LanguageLevel languageLevel = chunk.getLanguageLevel();
    CompilerUtil.addSourceCommandLineSwitch(jdk, languageLevel, commandLine);

    commandLine.add("-verbose");

    final String bootCp = chunk.getCompilationBootClasspath();

    final String classPath = chunk.getCompilationClasspath();
    commandLine.add("-bootclasspath");
    addClassPathValue(commandLine, bootCp);

    commandLine.add("-classpath");
    addClassPathValue(commandLine, classPath);

    if (isAnnotationProcessingMode) {
      commandLine.add("-s");
      commandLine.add(outputPath.replace('/', File.separatorChar));
      final String moduleOutputPath = CompilerPaths.getModuleOutputPath(chunk.getModules()[0], false);
      if (moduleOutputPath != null) {
        commandLine.add("-d");
        commandLine.add(moduleOutputPath.replace('/', File.separatorChar));
      }
    }
    else {
      commandLine.add("-d");
      commandLine.add(outputPath.replace('/', File.separatorChar));
    }
  }

  private static void addClassPathValue(@NotNull List<String> commandLine,
                                        @NotNull String cpString) throws IOException {
    commandLine.add(cpString);
  }

  private Sdk getJdkForStartupCommand(final ModuleChunk chunk) {
    final Sdk jdk = chunk.getJdk();
    if (ApplicationManager.getApplication().isUnitTestMode() && JavacConfiguration.getOptions(myProject, JavacConfiguration.class).isTestsUseExternalCompiler()) {
      final String jdkHomePath = CompilerConfigurationImpl.getTestsExternalCompilerHome();
      if (jdkHomePath == null) {
        throw new IllegalArgumentException("[TEST-MODE] Cannot determine home directory for JDK to use javac from");
      }
      // when running under Mock JDK use VM executable from the JDK on which the tests run
      return new MockJdkWrapper(jdkHomePath, jdk);
    }
    return jdk;
  }

  public void compileFinished() {
    FileUtil.asyncDelete(myTempFiles);
    myTempFiles.clear();
  }
}
TOP

Related Classes of com.google.errorprone.intellij.ErrorProneIdeaCompiler$MyException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.