def compile()

in src/main/scala/kotlin/AnalyzingKotlinCompiler.scala [48:229]


  def compile(
    @unused incrementalSources: Set[VirtualFile],
    @unused changes: DependencyChanges,
    callback: AnalysisCallback,
    classFileManager: ClassFileManager
  ): Unit = {
    val allSourceFiles = allSources.map(vf => converter.toPath(vf).toFile)

    val kotlinSources = allSourceFiles.filter { f =>
      val name = f.getName
      name.endsWith(".kt") || name.endsWith(".kts")
    }
    val javaSources = allSourceFiles.filter(_.getName.endsWith(".java"))

    if (kotlinSources.nonEmpty || javaSources.nonEmpty) {
      // Outline chunks of compiles so that .class files end up in right location
      val chunks: Map[Option[Path], Seq[VirtualFile]] = Map(Option(out.toPath) -> allSources)

      // Memoize the known class files in the Javac output location
      val memo = for { case (Some(outputPath), srcs) <- chunks } yield {
        val classFinder =
          if (outputPath.toString.endsWith(".jar")) new JarClassFinder(outputPath)
          else new DirectoryClassFinder(outputPath)
        (classFinder, classFinder.classes.pathsAndClose(), srcs)
      }

      def pluralizeSource(count: Int) =
        if (count == 1) "source" else "sources"

      val message =
        if (kotlinSources.nonEmpty) {
          val ktCount = kotlinSources.size
          if (javaSources.nonEmpty) {
            val javaCount = javaSources.size
            s"compiling $ktCount Kotlin ${pluralizeSource(ktCount)} and $javaCount Java ${pluralizeSource(javaCount)} to ${out.getAbsolutePath} ..."
          } else {
            s"compiling $ktCount Kotlin ${pluralizeSource(ktCount)} to ${out.getAbsolutePath} ..."
          }
        } else {
          val javaCount = javaSources.size
          s"compiling $javaCount Java ${pluralizeSource(javaCount)} to ${out.getAbsolutePath} ..."
        }
      s.log.info(message)

      // Record progress for Kotlin and Java compilation
      val somePhase = "<some phase>"
      val noPhase = "<no phase>"
      val kotlinCompilationPhase = "Kotlin compilation"
      val javaCompilationPhase = "Java compilation"
      val bytecodeAnalysisPhase = "Bytecode analysis"

      progressOpt.foreach { progress =>
        progress.startUnit(kotlinCompilationPhase, "")
        progress.advance(0, 3, somePhase, kotlinCompilationPhase)
      }

      if (kotlinSources.nonEmpty) {
        s.log.debug(s"compiling Kotlin sources: $kotlinSources")

        timed(kotlinCompilationPhase, s.log) {
          import language.reflectiveCalls
          val stub = KotlinStub(s, KotlinCompile.memoizedKotlinReflection(compilerClasspath))
          val args = stub.compilerArgs
          stub.parse(kotlinVersion, args.instance, "-Xallow-no-source-files" :: kotlinOptions.toList)
          args.multiPlatform = false
          args.noStdlib = true
          args.noReflect = true
          args.jvmTarget = jvmTarget
          args.moduleName = moduleName
          args.friendPaths = Array(out.getAbsolutePath)
          args.freeArgs = (kotlinSources ++ javaSources).map(_.getAbsolutePath).asJava
          val fcpjars = classpath.map(_.data.getAbsoluteFile).filter(_.exists())
          val (pluginjars, cpjars) = fcpjars.partition {
            grepjar(_)(_.getName.startsWith(
              "META-INF/services/org.jetbrains.kotlin.compiler.plugin"))
          }
          val cp = out.getAbsolutePath + File.pathSeparator + cpjars.mkString(File.pathSeparator)
          val pcp = pluginjars.map(_.getAbsolutePath).toArray
          args.classpath = Option(args.classpath[String]).fold(cp)(_ + File.pathSeparator + cp)
          args.pluginClasspaths = Option(args.pluginClasspaths[Array[String]]).fold(pcp)(_ ++ pcp)
          args.pluginOptions = Option(args.pluginOptions[Array[String]]).fold(
            kotlinPluginOptions.toArray)(_ ++ kotlinPluginOptions.toArray[String])
          args.destination = out.getAbsolutePath
          val success = stub.compile(args.instance)

          if (!success) {
            val msg = "kotlinc returned non-zero exit code"
            throw new CompileFailed(Array(args.toString), msg, reporter.problems())
          }
        }
      }

      val output = new SingleOutput {
        override def getOutputDirectory: File = out
      }

      progressOpt.foreach { progress =>
        progress.startUnit(javaCompilationPhase, "")
        progress.advance(1, 3, kotlinCompilationPhase, javaCompilationPhase)
      }

      if (javaSources.nonEmpty) {
        s.log.debug(s"compiling Java sources: $javaSources")

        timed(javaCompilationPhase, s.log) {
          val absoluteClasspath = converter.toVirtualFile(out.toPath) +: classpath.map(_.data.toPath).map(converter.toVirtualFile)
          val args = sbt.internal.inc.javac.JavaCompiler.commandArguments(
            absoluteClasspath,
            converter,
            javacOptions,
            scalaInstance,
            classpathOptions
          )
          val javaSrcs = javaSources.map(f => converter.toVirtualFile(f.toPath)).toArray
          val incToolOptions = IncToolOptions.of(
            Optional.of(classFileManager),
            useCustomizedFileManager
          )

          val success =
            javac.run(javaSrcs, args.toArray, output, incToolOptions, reporter, s.log)

          if (!success) {
            /* Assume that no Scalac problems are reported for a Javac-related
             * reporter. This relies on the incremental compiler will not run
             * Javac compilation if Scala compilation fails, which means that
             * the same reporter won't be used for `AnalyzingJavaCompiler`. */
            val msg = "javac returned non-zero exit code"
            throw new CompileFailed(args.toArray, msg, reporter.problems())
          }
        }
      }

      // Analysis
      // Read the API information from [[Class]] to analyze dependencies.
      def readAPI(source: VirtualFileRef, classes: Seq[Class[?]]): Set[(String, String)] = {
        val (apis, mainClasses, inherits) = ClassToAPI.process(classes)
        apis.foreach(callback.api(source, _))
        mainClasses.foreach(callback.mainClass(source, _))
        inherits.map {
          case (from, to) => (from.getName, to.getName)
        }
      }

      progressOpt.foreach { progress =>
        progress.startUnit(bytecodeAnalysisPhase, "")
        progress.advance(2, 3, javaCompilationPhase, bytecodeAnalysisPhase)
      }

      // Construct class loader to analyze dependencies of generated class files
      val loader = ClasspathUtil.toLoader(
        Seq(out.toPath) ++ classpath.files.map(_.toPath) ++ searchClasspath.map(converter.toPath)
      )

      timed(bytecodeAnalysisPhase, s.log) {
        for {
          (classFinder, oldClasses, srcs) <- memo
        } {
          val classes = classFinder.classes
          try {
            val newClasses = classes.paths.toSet -- oldClasses
            classFileManager.generated(newClasses.toArray.map(converter.toVirtualFile))
            JavaAnalyzeBridge(newClasses.toSeq, srcs, s.log, output, None)(callback, loader, readAPI)
          } finally classes.close()
        }
      }

      // After using the classloader it should be closed. Otherwise it will keep the accessed
      // jars open. Especially, when zinc is compiling directly to jar, that jar will be locked
      // not allowing to change it in further compilation cycles (on Windows).
      // This also affects jars in the classpath that come from dependency resolution.
      loader match {
        case u: URLClassLoader => u.close()
        case _                 => ()
      }

      // Report that we reached the end
      progressOpt.foreach { progress =>
        progress.advance(3, 3, bytecodeAnalysisPhase, noPhase)
      }
    }
  }