/*
 * Copyright 2014 The Kythe Authors. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.devtools.kythe.extractors.java;

import static com.google.common.base.StandardSystemProperty.JAVA_HOME;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;

import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteStreams;
import com.google.devtools.kythe.extractors.shared.CompilationDescription;
import com.google.devtools.kythe.extractors.shared.ExtractionException;
import com.google.devtools.kythe.extractors.shared.ExtractorUtils;
import com.google.devtools.kythe.extractors.shared.FileVNames;
import com.google.devtools.kythe.platform.java.JavacOptionsUtils.ModifiableOptions;
import com.google.devtools.kythe.proto.Analysis.CompilationUnit;
import com.google.devtools.kythe.proto.Analysis.CompilationUnit.FileInput;
import com.google.devtools.kythe.proto.Analysis.FileData;
import com.google.devtools.kythe.proto.Buildinfo.BuildDetails;
import com.google.devtools.kythe.proto.Java.JavaDetails;
import com.google.devtools.kythe.proto.Storage.VName;
import com.google.devtools.kythe.util.DeleteRecursively;
import com.google.protobuf.Any;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.file.CacheFSInfo;
import com.sun.tools.javac.file.FSInfo;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.util.Context;
import java.io.File;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.processing.Processor;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

/**
 * Extracts all required information (set of source files, class paths, and compiler options) from a
 * java compilation command and stores the information to replay the compilation.
 *
 * <p>The extractor runs the Javac compiler to get a exact description of all files required for the
 * compilation as a whole. It then creates CompilationUnit entries for each source file. We do not
 * do this on a per file basis as the Java Compiler takes too long to do this.
 */
public class JavaCompilationUnitExtractor {
  public static final String JAVA_DETAILS_URL = "kythe.io/proto/kythe.proto.JavaDetails";
  public static final String BUILD_DETAILS_URL = "kythe.io/proto/kythe.proto.BuildDetails";

  private static final Logger logger =
      Logger.getLogger(JavaCompilationUnitExtractor.class.getName());

  private static final String JDK_MODULE_PREFIX = "/modules/java.";
  private static final String MODULE_INFO_NAME = "module-info";
  private static final String SOURCE_JAR_ROOT = "!SOURCE_JAR!";

  private static String classJarRoot(Location location) {
    return String.format("!%s_JAR!", location);
  }

  // TODO(shahms): Use the proper methods when we can rely on JDK 9.
  private static final ClassLoader moduleClassLoader;

  static {
    ClassLoader loader = null;
    try {
      Object thisModule =
          Class.class.getMethod("getModule").invoke(JavaCompilationUnitExtractor.class);
      thisModule
          .getClass()
          .getMethod("addUses", Class.class)
          .invoke(thisModule, JavaCompiler.class);
      loader = (ClassLoader) thisModule.getClass().getMethod("getClassLoader").invoke(thisModule);
    } catch (ReflectiveOperationException e) {
      logger.info("Running on non-modular JDK, fallback compiler unavailable.");
    }
    moduleClassLoader = loader;
  }

  private static final String JAR_SCHEME = "jar";
  private final String jdkJar;
  private final String rootDirectory;
  private final FileVNames fileVNames;

  /**
   * Creates an instance of the JavaExtractor to store java compilation information in an .kindex
   * file.
   */
  public JavaCompilationUnitExtractor(String corpus) throws ExtractionException {
    this(corpus, ExtractorUtils.getCurrentWorkingDirectory());
  }

  /**
   * Creates an instance of the JavaExtractor to store java compilation information in an .kindex
   * file.
   */
  public JavaCompilationUnitExtractor(String corpus, String rootDirectory)
      throws ExtractionException {
    this(FileVNames.staticCorpus(corpus), rootDirectory);
  }

  /**
   * Creates an instance of the JavaExtractor to store java compilation information in an .kindex
   * file.
   */
  public JavaCompilationUnitExtractor(FileVNames fileVNames) throws ExtractionException {
    this(fileVNames, ExtractorUtils.getCurrentWorkingDirectory());
  }

  public JavaCompilationUnitExtractor(FileVNames fileVNames, String rootDirectory)
      throws ExtractionException {
    this.fileVNames = fileVNames;

    Path javaHome = Paths.get(JAVA_HOME.value()).getParent();
    try {
      // Remove trailing dots.  Interesting trivia: in some build systems,
      // the java.home variable is terminated with "/bin/..".
      // However, this is not the case for the class files
      // that we are trying to filter.
      this.jdkJar = javaHome.toRealPath(NOFOLLOW_LINKS).toString();
    } catch (IOException e) {
      throw new ExtractionException("JDK path not found: " + javaHome, e, false);
    }

    try {
      this.rootDirectory = Paths.get(rootDirectory).toRealPath().toString();
    } catch (IOException ioe) {
      throw new ExtractionException("Root directory does not exist", ioe, false);
    }
  }

  private CompilationUnit buildCompilationUnit(
      String target,
      Iterable<String> options,
      Iterable<FileInput> requiredInputs,
      boolean hasErrors,
      Set<String> newSourcePath,
      Set<String> newClassPath,
      Iterable<String> newBootClassPath,
      List<String> sourceFiles,
      String outputPath) {
    CompilationUnit.Builder unit = CompilationUnit.newBuilder();
    unit.setVName(VName.newBuilder().setSignature(target).setLanguage("java"));
    unit.addAllArgument(options);
    unit.setHasCompileErrors(hasErrors);
    unit.addAllRequiredInput(requiredInputs);
    for (String sourceFile : sourceFiles) {
      unit.addSourceFile(sourceFile);
    }
    unit.setOutputKey(outputPath);
    unit.addDetails(
        Any.newBuilder()
            .setTypeUrl(JAVA_DETAILS_URL)
            .setValue(
                JavaDetails.newBuilder()
                    .addAllClasspath(newClassPath)
                    .addAllBootclasspath(newBootClassPath)
                    .addAllSourcepath(newSourcePath)
                    .build()
                    .toByteString()));
    unit.addDetails(
        Any.newBuilder()
            .setTypeUrl(BUILD_DETAILS_URL)
            .setValue(BuildDetails.newBuilder().setBuildTarget(target).build().toByteString()));
    return unit.build();
  }

  /**
   * Indexes a compilation unit to the bigtable. The extraction process will try to build a minimum
   * set of what is needed to replay the compilation. To do this it runs the java compiler, and
   * tracks all .class & .java files that are needed. It then builds up a new classpath & sourcepath
   * that only contains the minimum set of paths required to replay the compilation.
   *
   * <p>New classpath: because we extract classes from the jars into a temp path that needs to be
   * set. Also we only use the classpaths that are actually used, not the ones that are provided.
   * New sourcepath: as we're doing a partial compilation, we need to set up the source path to
   * correctly load any files that are not the main compilation but are needed to perform
   * compilation. This is not required when doing a full compilation as all sources are
   * automatically loaded.
   *
   * <p>Next we store all required files in the bigtable and writes the CompilationUnit to the
   * bigtable.
   *
   * @throws ExtractionException if anything blocks the indexing to be completed.
   */
  public CompilationDescription extract(
      String target,
      Iterable<String> sources,
      Iterable<String> classpath,
      Iterable<String> bootclasspath,
      Iterable<String> sourcepath,
      Iterable<String> processorpath,
      Iterable<String> processors,
      Optional<Path> genSrcDir,
      Iterable<String> options,
      String outputPath)
      throws ExtractionException {
    Preconditions.checkNotNull(target);
    Preconditions.checkNotNull(sources);
    Preconditions.checkNotNull(classpath);
    Preconditions.checkNotNull(bootclasspath);
    Preconditions.checkNotNull(sourcepath);
    Preconditions.checkNotNull(processorpath);
    Preconditions.checkNotNull(processors);
    Preconditions.checkNotNull(genSrcDir);
    Preconditions.checkNotNull(options);
    Preconditions.checkNotNull(outputPath);

    AnalysisResults results;
    if (sources.iterator().hasNext()) {
      results =
          runJavaAnalysisToExtractCompilationDetails(
              sources,
              classpath,
              bootclasspath,
              sourcepath,
              processorpath,
              processors,
              genSrcDir,
              options);
    } else {
      results = new AnalysisResults();
    }

    List<FileData> fileContents = ExtractorUtils.convertBytesToFileDatas(results.fileContents);
    List<FileInput> compilationFileInputs =
        ExtractorUtils.toFileInputs(fileVNames, results.relativePaths::get, fileContents).stream()
            .map(
                input -> {
                  String sourceBasename = results.sourceFileNames.get(input.getInfo().getPath());
                  VName vname = input.getVName();
                  if (sourceBasename != null
                      && vname.getPath().endsWith(".java")
                      && !vname.getPath().endsWith(sourceBasename)) {
                    Path fixedPath = Paths.get(vname.getPath()).resolveSibling(sourceBasename);
                    vname = vname.toBuilder().setPath(fixedPath.toString()).build();
                    return input.toBuilder().setVName(vname).build();
                  }
                  return input;
                })
            .collect(toImmutableList());

    CompilationUnit compilationUnit =
        buildCompilationUnit(
            target,
            removeDestDirOptions(options),
            compilationFileInputs,
            results.hasErrors,
            results.newSourcePath,
            results.newClassPath,
            results.newBootClassPath,
            results.explicitSources,
            ExtractorUtils.tryMakeRelative(rootDirectory, outputPath));
    return new CompilationDescription(compilationUnit, fileContents);
  }

  /**
   * Returns a new list with the same options except header/source destination directory options.
   */
  private static ImmutableList<String> removeDestDirOptions(Iterable<String> options) {
    // TODO(#3671): Option.D needs to remain in for module support, fix either here or in indexing.
    return ModifiableOptions.of(options)
        .removeOptions(EnumSet.of(Option.D, Option.S, Option.H))
        .build();
  }

  /**
   * If the code has wildcard imports (e.g. import foo.bar.*) but doesn't actually use any of the
   * imports, errors will happen. We don't get callbacks for file open of these files (since they
   * aren't used) but when java runs it will report errors if it can't find any files to match the
   * wildcard. So we add one matching file here.
   */
  private void findOnDemandImportedFiles(
      Iterable<? extends CompilationUnitTree> compilationUnits,
      UsageAsInputReportingFileManager fileManager)
      throws ExtractionException {
    // Maps package names to source files that wildcard import them.
    Multimap<String, String> pkgs = HashMultimap.create();

    // Javac synthesizes an "import java.lang.*" for every compilation unit.
    pkgs.put("java.lang", "*.java");

    for (CompilationUnitTree unit : compilationUnits) {
      for (ImportTree importTree : unit.getImports()) {
        if (importTree.isStatic()) {
          continue;
        }
        String qualifiedIdentifier = importTree.getQualifiedIdentifier().toString();
        if (!qualifiedIdentifier.endsWith(".*")) {
          continue;
        }
        pkgs.put(
            qualifiedIdentifier.substring(0, qualifiedIdentifier.length() - 2),
            unit.getSourceFile().getName());
      }
    }

    for (Map.Entry<String, Collection<String>> pkg : pkgs.asMap().entrySet()) {
      try {
        JavaFileObject firstClass =
            Iterables.getFirst(
                fileManager.list(
                    StandardLocation.CLASS_PATH, pkg.getKey(), EnumSet.of(Kind.CLASS), false),
                null);
        if (firstClass == null) {
          firstClass =
              Iterables.getFirst(
                  fileManager.list(
                      StandardLocation.PLATFORM_CLASS_PATH,
                      pkg.getKey(),
                      EnumSet.of(Kind.CLASS),
                      false),
                  null);
        }
        if (firstClass != null) {
          firstClass.getCharContent(true);
        }
        JavaFileObject firstSource =
            Iterables.getFirst(
                fileManager.list(
                    StandardLocation.SOURCE_PATH, pkg.getKey(), EnumSet.of(Kind.SOURCE), false),
                null);
        if (firstSource != null) {
          firstSource.getCharContent(true);
        }
      } catch (IOException e) {
        throw new ExtractionException(
            String.format(
                "Unable to extract files used for on demand imports in {%s}",
                Joiner.on(", ").join(pkg.getValue())),
            e,
            false);
      }
    }
  }

  /**
   * Determines -sourcepath arguments to add to the compilation unit based on the package name. This
   * is needed as the sharded analysis will need to resolve dependent source files. Also locates
   * sources that do not follow the package == path convention and list them as explicit sources.
   */
  private void getAdditionalSourcePaths(
      Iterable<? extends CompilationUnitTree> compilationUnits, AnalysisResults results) {

    for (CompilationUnitTree compilationUnit : compilationUnits) {
      ExpressionTree packageExpression = compilationUnit.getPackageName();
      if (packageExpression != null) {
        String packageName = packageExpression.toString();
        if (!Strings.isNullOrEmpty(packageName)) {
          // If the source file specifies a package, we try to find that
          // package name in the path to the source file and assume
          // the correct sourcepath to add is the directory containing that
          // package.
          String packageSubDir = packageName.replace('.', '/');
          String path = compilationUnit.getSourceFile().toUri().getPath();
          // This needs to be lastIndexOf as there are source jars that
          // contain the same package name in the files contained in them
          // as the path the source jars live in. As we extract the source
          // jars, we end up with a double named path.
          int index = path.lastIndexOf(packageSubDir);
          if (index >= 0) {
            String root = ExtractorUtils.tryMakeRelative(rootDirectory, path.substring(0, index));
            results.newSourcePath.add(root);
          }
        }
      }
    }
  }

  private void findRequiredFiles(
      UsageAsInputReportingFileManager fileManager,
      Map<URI, String> sourceFiles,
      Optional<Path> genSrcDir,
      AnalysisResults results)
      throws ExtractionException {
    for (InputUsageRecord input : fileManager.getUsages()) {
      processRequiredInput(
          input.fileObject(), input.location(), fileManager, sourceFiles, genSrcDir, results);
    }
  }

  private void processRequiredInput(
      JavaFileObject requiredInput,
      Location location,
      UsageAsInputReportingFileManager fileManager,
      Map<URI, String> sourceFiles,
      Optional<Path> genSrcDir,
      AnalysisResults results)
      throws ExtractionException {
    URI uri = requiredInput.toUri();
    String entryPath;
    String jarPath = null;
    boolean isJarPath = false;

    {
      URLConnection conn;
      URL url;
      try {
        url = uri.toURL();
        conn = url.openConnection();
      } catch (IOException e) {
        throw new IOError(e);
      }
      if (conn instanceof JarURLConnection) {
        isJarPath = true;
        JarURLConnection jarConn = ((JarURLConnection) conn);
        jarPath = jarConn.getJarFileURL().getFile();
        // jar entries don't have a leading '/', and we expect
        // paths like "!CLASS_PATH_JAR!/com/foo/Bar.class"
        entryPath = "/" + jarConn.getEntryName();
      } else {
        entryPath = url.getFile();
      }
    }

    if (uri.getScheme().equals(JAR_SCHEME)) {
      isJarPath = true;
      uri = URI.create(uri.getRawSchemeSpecificPart());
    }

    switch (requiredInput.getKind()) {
      case CLASS:
      case SOURCE:
        break;
      case OTHER:
        if (uri.getPath().endsWith(".meta")) {
          break;
        }
        throw new IllegalStateException(String.format("Unsupported OTHER file kind: '%s'", uri));
      default:
        throw new IllegalStateException(
            String.format(
                "Unsupported java file kind: '%s' for '%s'", requiredInput.getKind().name(), uri));
    }
    String path = uri.getRawSchemeSpecificPart();

    // If the file was part of the JDK we do not store it as the JDK is tied
    // to the analyzer we'll run on this information later on.
    if ((isJarPath && jarPath.startsWith(jdkJar)) || path.startsWith(JDK_MODULE_PREFIX)) {
      return;
    }

    // Make the path relative to the indexer (e.g. a subdir of corpus/).
    // If not possible, we store the fullpath.
    String relativePath = ExtractorUtils.tryMakeRelative(rootDirectory, path);

    String strippedPath = relativePath;
    if (isJarPath) {
      // If the file came from a jar file, we strip that out as we don't care where it came from, it
      // was not as a source file in source control.  We turn it in to a fake path.  This is done so
      // we do not need to download the entire jar file for each file's compilation (e.g. instead of
      // downloading 200MB we only download 60K for analyzing the Kythe java indexer).
      switch (requiredInput.getKind()) {
        case CLASS:
          String root = classJarRoot(location);
          strippedPath = root + entryPath;
          (location == StandardLocation.PLATFORM_CLASS_PATH
                  ? results.newBootClassPath
                  : results.newClassPath)
              .add(root);
          break;
        case SOURCE:
          results.newSourcePath.add(SOURCE_JAR_ROOT);
          strippedPath = SOURCE_JAR_ROOT + entryPath;
          break;
        default:
          // TODO(#1845): we shouldn't need to throw an exception here because the above switch
          // statement means that we never hit this default, but the static analysis tools can't
          // figure that out.  Try to refactor this code to remove this issue.
          throw new IllegalStateException(
              String.format(
                  "Unsupported java file kind: '%s' for '%s'",
                  requiredInput.getKind().name(), uri));
      }
    } else {
      // If the class file was on disk, we need to infer the correct classpath to add.
      String binaryName = getBinaryNameForClass(fileManager, requiredInput);
      if (binaryName != null) {
        // Java package names map to folders on disk, so if we want to find the right directory
        // we replace each . with a /.
        String csubdir = binaryName.replace('.', '/');
        int cindex = strippedPath.indexOf(csubdir);
        if (cindex <= 0) {
          throw new ExtractionException(
              String.format(
                  "unable to infer classpath for %s from %s, %s",
                  strippedPath, csubdir, binaryName),
              false);
        } else {
          (location == StandardLocation.PLATFORM_CLASS_PATH
                  ? results.newBootClassPath
                  : results.newClassPath)
              .add(strippedPath.substring(0, cindex));
        }
      }
    }

    // Identify generated sources by checking if the source file is under the genSrcDir.
    if (genSrcDir.isPresent()
        && !isJarPath
        && requiredInput.getKind() == Kind.SOURCE
        && Paths.get(relativePath).startsWith(genSrcDir.get())) {
      results.explicitSources.add(strippedPath);
      results.newSourcePath.add(genSrcDir.get().toString());
    }

    if (!results.fileContents.containsKey(strippedPath)) {
      try {
        // Retrieve the contents of the file.
        InputStream stream = requiredInput.openInputStream();
        if (stream.markSupported()) {
          // The stream has already been read by the compiler, we need to reset it
          // so we can read it as well.
          stream.reset();
        }
        byte[] data = ByteStreams.toByteArray(stream);
        if (data.length == 0) {
          logger.warning(String.format("Empty java source file: %s", strippedPath));
        }
        results.fileContents.put(strippedPath, data);
        results.relativePaths.put(strippedPath, relativePath);
        if (sourceFiles.containsKey(requiredInput.toUri())) {
          results.sourceFileNames.put(strippedPath, sourceFiles.get(requiredInput.toUri()));
        }
      } catch (IOException e) {
        throw new ExtractionException(
            String.format("Unable to read file content of %s", strippedPath), false);
      }
    }
  }

  /** {@link Location}s that may contain class files. */
  private static final ImmutableSet<Location> CLASS_LOCATIONS =
      ImmutableSet.<Location>of(
          StandardLocation.CLASS_OUTPUT,
          StandardLocation.CLASS_PATH,
          StandardLocation.PLATFORM_CLASS_PATH);

  /**
   * Returns the location and binary name of a class file, or {@code null} if the file object is not
   * a class.
   */
  private static String getBinaryNameForClass(
      UsageAsInputReportingFileManager fileManager, JavaFileObject fileObject)
      throws ExtractionException {
    if (fileObject.getKind() != Kind.CLASS) {
      return null;
    }
    String binaryName;
    for (Location location : CLASS_LOCATIONS) {
      if ((binaryName = fileManager.inferBinaryName(location, fileObject)) != null) {
        return binaryName;
      }
    }
    if (fileObject.isNameCompatible(MODULE_INFO_NAME, Kind.CLASS)) {
      // Ignore automatic module-info.class files
      return null;
    }
    throw new ExtractionException(
        String.format("unable to infer classpath for %s", fileObject.getName()), false);
  }

  private static class AnalysisResults {
    // Map from strippedPath to an input's relative path to the corpus root.
    final Map<String, String> relativePaths = new LinkedHashMap<>();
    // Map from strippedPath to an input's contents.
    final Map<String, byte[]> fileContents = new LinkedHashMap<>();
    // Map from strippedPath to an input's true source basename. This is usually only needed for
    // non-public top-level classes where their filename does not match the path derived from their
    // fully-qualified name.
    final Map<String, String> sourceFileNames = new HashMap<>();

    // We build a new sourcepath & classpath that contain the minimum set of paths
    // as well as the modified set of paths that are needed to analyze the single compilation unit.
    // This is done to speed up analysis.
    final Set<String> newSourcePath = new LinkedHashSet<>();
    final Set<String> newClassPath = new LinkedHashSet<>();
    final Set<String> newBootClassPath = new LinkedHashSet<>();
    final List<String> explicitSources = new ArrayList<>();
    boolean hasErrors = false;
  }

  // Install NonResolvingCacheFSInfo into Context to avoid resolving symlinks.
  private void setupFSInfo(StandardJavaFileManager fileManager) {
    Context context = new Context();
    NonResolvingCacheFSInfo.preRegister(context);
    ((JavacFileManager) fileManager).setContext(context);
  }

  // FSInfo class which does not resolve symlinks when canonicalizing paths.
  private static class NonResolvingCacheFSInfo extends CacheFSInfo {
    public static void preRegister(Context context) {
      context.put(
          FSInfo.class,
          new Context.Factory<FSInfo>() {
            @Override
            public FSInfo make(Context c) {
              FSInfo instance = new NonResolvingCacheFSInfo();
              c.put(FSInfo.class, instance);
              return instance;
            }
          });
    }

    @Override
    public Path getCanonicalFile(Path file) {
      return file.toAbsolutePath();
    }
  }

  private AnalysisResults runJavaAnalysisToExtractCompilationDetails(
      Iterable<String> sources,
      Iterable<String> classpath,
      Iterable<String> bootclasspath,
      Iterable<String> sourcepath,
      Iterable<String> processorpath,
      Iterable<String> processors,
      Optional<Path> genSrcDir,
      Iterable<String> options)
      throws ExtractionException {

    AnalysisResults results = new AnalysisResults();

    // We will initialize and run the Javac compiler to detect which dependencies
    // the current compilation has.
    JavaCompiler compiler = findJavaCompiler();
    if (compiler == null) {
      // TODO(schroederc): provide link to further context
      throw new IllegalStateException(
          "Could not get system Java compiler; are you missing the JDK?");
    }

    DiagnosticCollector<JavaFileObject> diagnosticsCollector = new DiagnosticCollector<>();

    StandardJavaFileManager standardFileManager =
        compiler.getStandardFileManager(diagnosticsCollector, null, null);
    setupFSInfo(standardFileManager);

    // We insert a filemanager that wraps the standard filemanager and records the compiler's
    // usage of .java & .class files.
    final UsageAsInputReportingFileManager fileManager =
        new UsageAsInputReportingFileManager(standardFileManager);

    Iterable<? extends JavaFileObject> sourceFiles = fileManager.getJavaFileForSources(sources);

    // Generate class files in a temporary directory
    Path tempDir;
    try {
      tempDir = Files.createTempDirectory("javac_extractor");
    } catch (IOException ioe) {
      throw new ExtractionException(
          "Unable to create temporary .class output directory", ioe, true);
    }
    List<String> completeOptions =
        completeCompilerOptions(
            standardFileManager,
            options,
            classpath,
            bootclasspath,
            sourcepath,
            processorpath,
            tempDir);

    final List<CompilationUnitTree> compilationUnits = new ArrayList<>();
    Symtab syms;
    try {
      // Launch the java compiler with our modified settings and the filemanager wrapper
      CompilationTask task =
          compiler.getTask(
              null, fileManager, diagnosticsCollector, completeOptions, null, sourceFiles);

      ClassLoader loader = processingClassloader(classpath, processorpath);

      List<Processor> procs = new ArrayList<>();

      // Add any processors passed as flags.
      for (String processor : processors) {
        try {
          procs.add(
              loader
                  .loadClass(processor)
                  .asSubclass(Processor.class)
                  .getConstructor()
                  .newInstance());
        } catch (Throwable e) {
          throw new ExtractionException("Bad processor entry: " + processor, e, false);
        }
      }

      if (procs.isEmpty()) {
        // If no --processors were passed, add any processors registered in the META-INF/services
        // configuration.
        for (Processor proc : ServiceLoader.load(Processor.class, loader)) {
          procs.add(proc);
        }
      }

      procs.add(new ProcessAnnotation(fileManager));

      JavacTask javacTask = (JavacTask) task;
      javacTask.setProcessors(procs);
      syms = Symtab.instance(((JavacTaskImpl) javacTask).getContext());

      javacTask.addTaskListener(
          new TaskListener() {
            @Override
            public void finished(TaskEvent e) {
              if (e.getKind() == TaskEvent.Kind.PARSE) {
                compilationUnits.add(e.getCompilationUnit());
              }
            }

            @Override
            public void started(TaskEvent e) {}
          });

      try {
        // In order for the compiler to load all required .java & .class files we need to have it go
        // through parsing, analysis & generate phases.  Unfortunately the latter is needed to get a
        // complete list, this was found as we were breaking on analyzing certain files.
        // JavacTask#call() subsumes parse() and generate(), but calling those methods directly may
        // silently ignore fatal errors.
        results.hasErrors = !javacTask.call();
      } catch (com.sun.tools.javac.util.Abort e) {
        // Type resolution issues, the diagnostics will give hints on what's going wrong.
        for (Diagnostic<? extends JavaFileObject> diagnostic :
            diagnosticsCollector.getDiagnostics()) {
          if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
            logger.severe("Fatal error in compiler: " + diagnostic.getMessage(Locale.ENGLISH));
          }
        }
        throw new ExtractionException("Fatal error while running javac compiler.", e, false);
      }

      // If we encountered any compilation errors, we report them even though we
      // still store the compilation information for this set of sources.
      for (Diagnostic<? extends JavaFileObject> diag : diagnosticsCollector.getDiagnostics()) {
        if (diag.getKind() == Diagnostic.Kind.ERROR) {
          results.hasErrors = true;
          if (diag.getSource() != null) {
            logger.severe(
                String.format(
                    "compiler error: %s(%d): %s",
                    diag.getSource().getName(),
                    diag.getLineNumber(),
                    diag.getMessage(Locale.ENGLISH)));
          } else {
            logger.severe("compiler error: " + diag.getMessage(Locale.ENGLISH));
          }
        }
      }

      // Ensure generated source directory is relative to root.
      genSrcDir =
          genSrcDir.transform(
              p -> Paths.get(ExtractorUtils.tryMakeRelative(rootDirectory, p.toString())));

      for (String source : sources) {
        results.explicitSources.add(ExtractorUtils.tryMakeRelative(rootDirectory, source));
      }

      getAdditionalSourcePaths(compilationUnits, results);

      // Find files potentially used for resolving .* imports.
      findOnDemandImportedFiles(compilationUnits, fileManager);
      // We accumulate all file contents from the java compiler so we can store it in the bigtable.
      findRequiredFiles(fileManager, mapClassesToSources(syms), genSrcDir, results);
    } finally {
      try {
        DeleteRecursively.delete(tempDir);
      } catch (IOException ioe) {
        logger.log(Level.SEVERE, "Failed to delete temporary directory " + tempDir, ioe);
      }
    }

    return results;
  }

  /** Sets the given location using command-line flags and the FileManager API. */
  private static void setLocation(
      ModifiableOptions options,
      StandardJavaFileManager fileManager,
      Iterable<String> searchpath,
      String flag,
      StandardLocation location)
      throws ExtractionException {
    String joined = Joiner.on(":").join(searchpath);
    if (!joined.isEmpty()) {
      options.add(flag);
      options.add(joined);
      try {
        List<File> files = new ArrayList<>();
        for (String elt : searchpath) {
          files.add(new File(elt));
        }
        fileManager.setLocation(location, files);
      } catch (IOException e) {
        throw new ExtractionException(String.format("Couldn't set %s", location), e, false);
      }
    }
  }

  /** Create the ClassLoader to use for annotation processors. */
  private static ClassLoader processingClassloader(
      Iterable<String> classpath, Iterable<String> processorpath) throws ExtractionException {
    // If javac is run with -processor set and -processorpath *unset*, it will fall back to
    // searching the regular classpath for annotation processors.
    if (Iterables.isEmpty(processorpath)) {
      processorpath = classpath;
    }

    List<URL> urls = new ArrayList<>();
    for (String path : processorpath) {
      try {
        urls.add(new File(path).toURI().toURL());
      } catch (MalformedURLException e) {
        throw new ExtractionException("Bad processorpath entry", e, false);
      }
    }
    ClassLoader parent = new MaskedClassLoader();
    return new URLClassLoader(Iterables.toArray(urls, URL.class), parent);
  }

  /** Isolated classloader for annotation processors, to avoid skew with the ambient classpath. */
  private static class MaskedClassLoader extends ClassLoader {
    private MaskedClassLoader() {
      // delegate only to the bootclasspath
      super(getPlatformClassLoader());
    }

    // TODO(#2451): remove reflection and call ClassLoader.getPlatformClassLoader() directly
    // once JDK 8 compatibility is no longer required.
    public static ClassLoader getPlatformClassLoader() {
      try {
        // In JDK 9, all platform classes are visible to the platform class loader:
        // https://docs.oracle.com/javase/9/docs/api/java/lang/ClassLoader.html#getPlatformClassLoader--
        return (ClassLoader) ClassLoader.class.getMethod("getPlatformClassLoader").invoke(null);
      } catch (ReflectiveOperationException e) {
        // In earlier releases, set 'null' as the parent to delegate to the boot class loader.
        return null;
      }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
      if (name.startsWith("com.sun.source.") || name.startsWith("com.sun.tools.")) {
        return JavaCompilationUnitExtractor.class.getClassLoader().loadClass(name);
      }
      throw new ClassNotFoundException(name);
    }
  }

  /**
   * Completes the given raw compiler options with the given classpath, sourcepath, and temporary
   * destination directory. Only options supported by the Java compiler will be within the returned
   * {@link List}.
   */
  private static ImmutableList<String> completeCompilerOptions(
      StandardJavaFileManager standardFileManager,
      Iterable<String> rawOptions,
      Iterable<String> classpath,
      Iterable<String> bootclasspath,
      Iterable<String> sourcepath,
      Iterable<String> processorpath,
      Path tempDestinationDir)
      throws ExtractionException {

    ModifiableOptions completeOptions =
        ModifiableOptions.of(rawOptions)
            .removeUnsupportedOptions()
            .ensureEncodingSet(StandardCharsets.UTF_8);
    // Android always uses this option.
    // TODO(asmundak): needs more work before contributing upstream.
    completeOptions.add("-XDstringConcat=inline");
    setLocation(
        completeOptions, standardFileManager, classpath, "-cp", StandardLocation.CLASS_PATH);
    setLocation(
        completeOptions,
        standardFileManager,
        sourcepath,
        "-sourcepath",
        StandardLocation.SOURCE_PATH);
    setLocation(
        completeOptions,
        standardFileManager,
        processorpath,
        "-processorpath",
        StandardLocation.ANNOTATION_PROCESSOR_PATH);
    setLocation(
        completeOptions,
        standardFileManager,
        bootclasspath,
        "-bootclasspath",
        StandardLocation.PLATFORM_CLASS_PATH);

    return completeOptions
        .removeOptions(EnumSet.of(Option.D))
        .add("-d")
        .add(tempDestinationDir.toString())
        .build();
  }

  private static JavaCompiler findJavaCompiler() {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    if (compiler == null && moduleClassLoader != null) {
      // This is all a bit of a hack to be able to extract OpenJDK itself, which
      // uses a bootstrap compiler and a lot of JDK options to compile itself.
      // Notably, when using modules the system compiler is inhibited and the actual compiler
      // resides in jdk.compiler.iterim.  Rather than hard-code this, just fall back to the first
      // JavaCompiler we can find.
      logger.warning("Unable to find system compiler, using first available.");
      for (JavaCompiler found : ServiceLoader.load(JavaCompiler.class, moduleClassLoader)) {
        return found;
      }
    }
    return compiler;
  }

  /** Returns a map from a classfile's {@link URI} to its sourcefile path's basename. */
  private static Map<URI, String> mapClassesToSources(Symtab syms) {
    Map<URI, String> sourceBaseNames = new HashMap<>();
    for (ClassSymbol sym : syms.getAllClasses()) {
      if (sym.sourcefile != null && sym.classfile != null) {
        String path = sym.sourcefile.toUri().getPath();
        if (path != null) {
          String basename = Paths.get(path).getFileName().toString();
          if (!basename.endsWith(".java") && !basename.endsWith(".kt")) {
            logger.warning(String.format("Invalid sourcefile name: '%s'", basename));
          }
          sourceBaseNames.put(sym.classfile.toUri(), basename);
        }
      }
    }
    return sourceBaseNames;
  }
}
