diff --git a/build.sbt b/build.sbt index f7ea2eff57e9..3c2d1deb300d 100644 --- a/build.sbt +++ b/build.sbt @@ -712,7 +712,7 @@ lazy val partest = configureAsSubproject(project) ) lazy val tastytest = configureAsSubproject(project) - .dependsOn(library, reflect, compiler) + .dependsOn(library, reflect, compiler, scaladoc) .settings(disableDocs) .settings(fatalWarningsSettings) .settings(publish / skip := true) diff --git a/src/tastytest/scala/tools/tastytest/Scaladoc.scala b/src/tastytest/scala/tools/tastytest/Scaladoc.scala new file mode 100644 index 000000000000..8d61cc96ef0c --- /dev/null +++ b/src/tastytest/scala/tools/tastytest/Scaladoc.scala @@ -0,0 +1,76 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala.tools.tastytest + +import scala.collection.immutable.ArraySeq +import scala.util.{ Try, Success, chaining }, chaining._ +import scala.tools.nsc.{ reporters}, reporters.{Reporter, ConsoleReporter} +import java.io.OutputStream +import java.io.PrintWriter + +import scala.tools.nsc.{ScalaDoc => RealScaladoc, doc} +import scala.reflect.internal.util.NoPosition + +object Scaladoc extends Script.Command { + + def scaladoc(out: String, additionalSettings: Seq[String], sources: String*): Try[Boolean] = + scaladoc(Console.out, out, additionalSettings, sources:_*) + + def scaladoc(writer: OutputStream, out: String, additionalSettings: Seq[String], sources: String*) = { + + def setup(args: Seq[String]): (Reporter, doc.Settings, RealScaladoc.Command) = { + lazy val (reporter: Reporter, docSettings) = { + val docSettings = new doc.Settings(msg => reporter.error(NoPosition, msg), msg => reporter.echo(msg)) + val pwriter = new PrintWriter(writer, true) + (new ConsoleReporter(docSettings, Console.in, pwriter).tap(_.shortname = true), docSettings) + } + (reporter, docSettings, new RealScaladoc.Command(args.toList, docSettings)) + } + + def compile(args: String*): Try[Boolean] = { + val (reporter, docSettings, command) = setup(args) + Try { + assert(command.files.nonEmpty, "no files to compile") + try { new doc.DocFactory(reporter, docSettings).document(command.files) } + finally reporter.finish() + }.map(_ => !reporter.hasErrors) + } + + if (sources.isEmpty) { + Success(true) + } + else { + val settings = Array( + "-d", out, + "-classpath", out, + "-deprecation", + "-Xfatal-warnings", + "-usejavacp" + ) ++ additionalSettings ++ sources + compile(ArraySeq.unsafeWrapArray(settings):_*) + } + } + + val commandName: String = "scaladoc" + val describe: String = s"$commandName " + + def process(args: String*): Int = { + if (args.length < 2) { + println(red(s"please provide at least 2 arguments in sub-command: $describe")) + return 1 + } + val Seq(out, src, additionalArgs @ _*) = args: @unchecked + val success = scaladoc(out, additionalArgs, src).get + if (success) 0 else 1 + } +} diff --git a/src/tastytest/scala/tools/tastytest/TastyTest.scala b/src/tastytest/scala/tools/tastytest/TastyTest.scala index 32777413ca8f..4b9c7bc3fd17 100644 --- a/src/tastytest/scala/tools/tastytest/TastyTest.scala +++ b/src/tastytest/scala/tools/tastytest/TastyTest.scala @@ -99,7 +99,21 @@ object TastyTest { _ <- scalacPos(out, individualCapable=true, sourceRoot=srcRoot/src/"src-2", additionalSettings, src2:_*) } yield () - /**Simulates a Scala 2 application that depends on a Scala 3 library, and is expected to fail compilation. + + /**Simulates running scaladoc on a Scala 2 library that depends on a Scala 3 library. + * Steps: + * 1) compile all Scala files in `src-3` with scala 3 to `out`, with `out` as the classpath + * 2) compile all Scala files in `src-2` with scaladoc (scala 2) to `out`, with `out` as the classpath + */ + def posDocSuite(src: String, srcRoot: String, pkgName: String, outDir: Option[String], additionalSettings: Seq[String], additionalDottySettings: Seq[String])(implicit cl: Dotc.ClassLoader): Try[Unit] = for { + (src2, src3) <- get2And3Sources(srcRoot/src, src2Filters = Set(Scala), src3Filters = Set(Scala)) + _ = log(s"Sources to compile under test: ${src2.map(cyan).mkString(", ")}") + out <- outDir.fold(tempDir(pkgName))(dir) + _ <- dotcPos(out, sourceRoot=srcRoot/src/"src-3", additionalDottySettings, src3:_*) + _ <- scaladoc(out, sourceRoot=srcRoot/src/"src-2", additionalSettings, src2:_*) + } yield () + + /**Simulates a Scala 2 application that depends on a Scala 3 library, and is expected to fail compilation. * Steps: * 1) compile all Scala files in `src-3` with scala 3 to `out` * 2) attempt to compile all Scala files in `src-2` with scala 2 to `out`, with `out` as the classpath. @@ -225,6 +239,12 @@ object TastyTest { successWhen(res)("scalac failed to compile sources.") } + private def scaladoc(out: String, sourceRoot: String, additionalSettings: Seq[String], sources: String*): Try[Unit] = { + log(s"compiling sources in ${yellow(sourceRoot)} with scalac.") + val res = Scaladoc.scaladoc(out, "-Ytasty-reader" +: additionalSettings, sources:_*) + successWhen(res)("scaladoc failed to compile resources") + } + private def scalacNeg(out: String, additionalSettings: Seq[String], files: String*): Try[Unit] = scalacNeg(out, extraCp = None, additionalSettings, files:_*) diff --git a/test/tasty/pos-doctool/src-2/app/Main.scala b/test/tasty/pos-doctool/src-2/app/Main.scala new file mode 100644 index 000000000000..d9ef49e0f357 --- /dev/null +++ b/test/tasty/pos-doctool/src-2/app/Main.scala @@ -0,0 +1,8 @@ +package app + +object Main { + def main(args: Array[String]): Unit = { + println(testlib.ADT.SingletonCase) + println(testlib.ADT.ClassCase("foo")) + } +} diff --git a/test/tasty/pos-doctool/src-3/testlib/ADT.scala b/test/tasty/pos-doctool/src-3/testlib/ADT.scala new file mode 100644 index 000000000000..0a867618d309 --- /dev/null +++ b/test/tasty/pos-doctool/src-3/testlib/ADT.scala @@ -0,0 +1,5 @@ +package testlib + +enum ADT: + case SingletonCase + case ClassCase(x: String) diff --git a/test/tasty/test/scala/tools/tastytest/TastyTestJUnit.scala b/test/tasty/test/scala/tools/tastytest/TastyTestJUnit.scala index 324163ff847c..8199e2e4a58b 100644 --- a/test/tasty/test/scala/tools/tastytest/TastyTestJUnit.scala +++ b/test/tasty/test/scala/tools/tastytest/TastyTestJUnit.scala @@ -51,6 +51,15 @@ class TastyTestJUnit { additionalDottySettings = Nil ).eval + @test def posDoctool(): Unit = TastyTest.posDocSuite( + src = "pos-doctool", + srcRoot = assertPropIsSet(propSrc), + pkgName = assertPropIsSet(propPkgName), + outDir = None, + additionalSettings = Nil, + additionalDottySettings = Nil + ).eval + @test def neg(): Unit = TastyTest.negSuite( src = "neg", srcRoot = assertPropIsSet(propSrc),