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

sbt.internal.inc.RawCompiler.scala Maven / Gradle / Ivy

There is a newer version: 1.10.4
Show newest version
/*
 * Zinc - The incremental compiler for Scala.
 * Copyright Scala Center, Lightbend, and Mark Harrah
 *
 * Licensed under Apache License 2.0
 * SPDX-License-Identifier: Apache-2.0
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package sbt
package internal
package inc

import java.nio.file.Path
import sbt.internal.util.FeedbackProvidedException
import xsbti.compile.{ ClasspathOptions, ScalaInstance => XScalaInstance }

/**
 * Provide a basic interface to the Scala Compiler that does not analyze
 * dependencies nor does any kind of incremental compilation.
 *
 * This interface is called in the same virtual machine where it's instantiated.
 * It's useful for raw compilation of sources, such as those of the compiler
 * interface (bridge) and plugin code.
 *
 * @param scalaInstance The Scala instance to which we create a compiler.
 * @param cp The classpath options that dictate which classpath entries to use.
 * @param log The logger where the Scalac compiler creation is reported.
 */
class RawCompiler(val scalaInstance: XScalaInstance, cp: ClasspathOptions, log: sbt.util.Logger) {

  /**
   * Run the compiler with the usual compiler inputs.
   *
   * This method supports both Scalac and Dotty. To use a concrete compiler,
   * you need to pass the `ScalaInstance` associated with it.
   *
   * @param sources The sources to be compiled.
   * @param classpath The classpath to be used at compile time.
   * @param outputDirectory The directory in which the class files are placed.
   * @param options The auxiliary options to Scala compilers.
   */
  def apply(
      sources: Seq[Path],
      classpath: Seq[Path],
      outputDirectory: Path,
      options: Seq[String]
  ): Unit = {

    // Run the compiler and get the reporter attached to it.
    def getReporter(fqn: String, args: Array[String], isDotty: Boolean): AnyRef = {
      val mainClass = Class.forName(fqn, true, scalaInstance.loader)
      val process = mainClass.getMethod("process", classOf[Array[String]])
      val potentialReporter = process.invoke(null, args)
      if (isDotty) potentialReporter
      else mainClass.getMethod("reporter").invoke(null)
    }

    // Make sure that methods exist so that reflection is safe (trick)
    import scala.tools.nsc.Main.{ process => _, reporter => _ }
    val uniqueCompilerVersion = scalaInstance.actualVersion
    val compilerOut = Some(outputDirectory)
    val arguments = compilerArguments.makeArguments(sources, classpath, compilerOut, options)
    val args = arguments.toArray

    log.debug(
      s"""Creating plain compiler interface for $uniqueCompilerVersion.
        |  > Arguments: ${arguments.mkString("\n\t", "\n\t", "")}
      """.stripMargin
    )

    val reporter = {
      if (ScalaInstance.isDotty(scalaInstance.version))
        getReporter("dotty.tools.dotc.Main", args, isDotty = true)
      else getReporter("scala.tools.nsc.Main", args, isDotty = false)
    }

    checkForFailure(reporter, arguments.toArray)
  }

  protected def checkForFailure(reporter: AnyRef, args: Array[String]): Unit = {
    val hasErrorsMethod = reporter.getClass.getMethod("hasErrors")
    val failed = hasErrorsMethod.invoke(reporter).asInstanceOf[Boolean]
    if (failed) throw new CompileFailed(args, "Plain compile failed", Array())
  }

  /**
   * Return the correct compiler arguments for the given `ScalaInstance`
   * and `ClasspathOptions`. Keep in mind that these compiler arguments are
   * specific to a concrete Scala version.
   */
  def compilerArguments = new CompilerArguments(scalaInstance, cp)
}

class CompileFailed(
    val arguments: Array[String],
    override val toString: String,
    val problems: Array[xsbti.Problem],
    cause: Throwable
) extends xsbti.CompileFailed(cause)
    with FeedbackProvidedException {

  def this(arguments: Array[String], toString: String, problems: Array[xsbti.Problem]) = {
    this(arguments, toString, problems, null)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy