Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport "Revert #17623" to LTS #18963

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ case class Module(rootPackage: Member, members: Map[DRI, Member])

object ScalaModuleProvider:
def mkModule()(using ctx: DocContext): Module =
val (result, rootDoc) = ScaladocTastyInspector.loadDocs()
val (result, rootDoc) = ScaladocTastyInspector().result()
val (rootPck, rest) = result.partition(_.name == "API")
val (emptyPackages, nonemptyPackages) = (rest ++ rootPck.flatMap(_.members))
.filter(p => p.members.nonEmpty || p.docs.nonEmpty).sortBy(_.name)
Expand Down
65 changes: 31 additions & 34 deletions scaladoc/src/dotty/tools/scaladoc/tasty/TastyParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package tasty
import java.util.regex.Pattern

import scala.util.{Try, Success, Failure}
import scala.tasty.inspector.{TastyInspector, Inspector, Tasty}
import scala.tasty.inspector.DocTastyInspector
import scala.quoted._

import dotty.tools.dotc
Expand All @@ -24,12 +24,24 @@ import ScaladocSupport._
*
* Delegates most of the work to [[TastyParser]] [[dotty.tools.scaladoc.tasty.TastyParser]].
*/
case class ScaladocTastyInspector()(using ctx: DocContext) extends Inspector:
case class ScaladocTastyInspector()(using ctx: DocContext) extends DocTastyInspector:

private val topLevels = Seq.newBuilder[(String, Member)]
private var rootDoc: Option[Comment] = None

def inspect(using Quotes)(tastys: List[scala.tasty.inspector.Tasty[quotes.type]]): Unit =
def processCompilationUnit(using Quotes)(root: reflect.Tree): Unit = ()

override def postProcess(using Quotes): Unit =
// hack into the compiler to get a list of all top-level trees
// in principle, to do this, one would collect trees in processCompilationUnit
// however, path-dependent types disallow doing so w/o using casts
inline def hackForeachTree(thunk: reflect.Tree => Unit): Unit =
given dctx: dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
dctx.run.nn.units.foreach { compilationUnit =>
// mirrors code from TastyInspector
thunk(compilationUnit.tpdTree.asInstanceOf[reflect.Tree])
}

val symbolsToSkip: Set[reflect.Symbol] =
ctx.args.identifiersToSkip.flatMap { ref =>
val qrSymbol = reflect.Symbol
Expand Down Expand Up @@ -104,8 +116,7 @@ case class ScaladocTastyInspector()(using ctx: DocContext) extends Inspector:
rootDoc = Some(parseCommentString(using parser.qctx, summon[DocContext])(content, topLevelPck, None))
}

for tasty <- tastys do {
val root = tasty.ast
hackForeachTree { root =>
if !isSkipped(root.symbol) then
val treeRoot = root.asInstanceOf[parser.qctx.reflect.Tree]
processRootDocIfNeeded(treeRoot)
Expand All @@ -127,47 +138,33 @@ case class ScaladocTastyInspector()(using ctx: DocContext) extends Inspector:
topLevels += "scala" -> Member(scalaPckg.fullName, "", scalaPckg.dri, Kind.Package)
topLevels += mergeAnyRefAliasAndObject(parser)



def mergeAnyRefAliasAndObject(parser: TastyParser) =
import parser.qctx.reflect._
val javaLangObjectDef = defn.ObjectClass.tree.asInstanceOf[ClassDef]
val objectMembers = parser.extractPatchedMembers(javaLangObjectDef)
val aM = parser.parseTypeDef(defn.AnyRefClass.tree.asInstanceOf[TypeDef])
"scala" -> aM.copy(
kind = Kind.Class(Nil, Nil),
members = objectMembers
)

object ScaladocTastyInspector:

def loadDocs()(using ctx: DocContext): (List[Member], Option[Comment]) =
def result(): (List[Member], Option[Comment]) =
topLevels.clear()
rootDoc = None
val filePaths = ctx.args.tastyFiles.map(_.getAbsolutePath).toList
val classpath = ctx.args.classpath.split(java.io.File.pathSeparator).toList

val inspector = new ScaladocTastyInspector

val (tastyPaths, nonTastyPaths) = filePaths.partition(_.endsWith(".tasty"))
val (jarPaths, invalidPaths) = nonTastyPaths.partition(_.endsWith(".jar"))

for invalidPath <- invalidPaths do
report.error("File extension is not `tasty` or `jar`: " + invalidPath)

if tastyPaths.nonEmpty then
TastyInspector.inspectAllTastyFiles(tastyPaths, jarPaths, classpath)(inspector)
if filePaths.nonEmpty then inspectFilesInContext(classpath, filePaths)

val all = inspector.topLevels.result()
val all = topLevels.result()
all.groupBy(_._1).map { case (pckName, members) =>
val (pcks, rest) = members.map(_._2).partition(_.kind == Kind.Package)
val basePck = pcks.reduce( (p1, p2) =>
val withNewMembers = p1.withNewMembers(p2.members)
if withNewMembers.docs.isEmpty then withNewMembers.withDocs(p2.docs) else withNewMembers
)
basePck.withMembers((basePck.members ++ rest).sortBy(_.name))
}.toList -> inspector.rootDoc

end ScaladocTastyInspector
}.toList -> rootDoc

def mergeAnyRefAliasAndObject(parser: TastyParser) =
import parser.qctx.reflect._
val javaLangObjectDef = defn.ObjectClass.tree.asInstanceOf[ClassDef]
val objectMembers = parser.extractPatchedMembers(javaLangObjectDef)
val aM = parser.parseTypeDef(defn.AnyRefClass.tree.asInstanceOf[TypeDef])
"scala" -> aM.copy(
kind = Kind.Class(Nil, Nil),
members = objectMembers
)
/** Parses a single Tasty compilation unit. */
case class TastyParser(
qctx: Quotes,
Expand Down
9 changes: 9 additions & 0 deletions scaladoc/src/scala/tasty/inspector/DocTastyInspector.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package scala.tasty.inspector

import dotty.tools.dotc.core.Contexts.Context

abstract class DocTastyInspector extends OldTastyInspector:
def inspectFilesInDocContext(
classpath: List[String],
filePaths: List[String])(
using Context): Unit = inspectFilesInContext(classpath, filePaths)
33 changes: 0 additions & 33 deletions scaladoc/src/scala/tasty/inspector/Inspector.scala

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// Copy of tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala
// FIXME remove this copy of the file

package scala.tasty.inspector

import scala.quoted._
Expand All @@ -13,43 +10,45 @@ import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Mode
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.fromtasty._
import dotty.tools.dotc.quoted.QuotesCache
import dotty.tools.dotc.util.ClasspathFromClassloader
import dotty.tools.dotc.CompilationUnit
import dotty.tools.unsupported
import dotty.tools.dotc.report

import java.io.File.pathSeparator

object TastyInspector:
// COPY OF OLD IMPLEMENTATION
// TODO: update to new implementation
trait OldTastyInspector:
self =>

/** Process a TASTy file using TASTy reflect */
protected def processCompilationUnit(using Quotes)(root: quotes.reflect.Tree): Unit

/** Called after all compilation units are processed */
protected def postProcess(using Quotes): Unit = ()

/** Load and process TASTy files using TASTy reflect
*
* @param tastyFiles List of paths of `.tasty` files
*
* @return boolean value indicating whether the process succeeded
*/
def inspectTastyFiles(tastyFiles: List[String])(inspector: Inspector): Boolean =
inspectAllTastyFiles(tastyFiles, Nil, Nil)(inspector)
def inspectTastyFiles(tastyFiles: List[String]): Boolean =
inspectAllTastyFiles(tastyFiles, Nil, Nil)

/** Load and process TASTy files in a `jar` file using TASTy reflect
*
* @param jars Path of `.jar` file
*
* @return boolean value indicating whether the process succeeded
*/
def inspectTastyFilesInJar(jar: String)(inspector: Inspector): Boolean =
inspectAllTastyFiles(Nil, List(jar), Nil)(inspector)
def inspectTastyFilesInJar(jar: String): Boolean =
inspectAllTastyFiles(Nil, List(jar), Nil)

/** Load and process TASTy files using TASTy reflect
*
* @param tastyFiles List of paths of `.tasty` files
* @param jars List of path of `.jar` files
* @param dependenciesClasspath Classpath with extra dependencies needed to load class in the `.tasty` files
*
* @return boolean value indicating whether the process succeeded
*/
def inspectAllTastyFiles(tastyFiles: List[String], jars: List[String], dependenciesClasspath: List[String])(inspector: Inspector): Boolean =
def inspectAllTastyFiles(tastyFiles: List[String], jars: List[String], dependenciesClasspath: List[String]): Boolean =
def checkFile(fileName: String, ext: String): Unit =
val file = dotty.tools.io.Path(fileName)
if file.extension != ext then
Expand All @@ -59,30 +58,40 @@ object TastyInspector:
tastyFiles.foreach(checkFile(_, "tasty"))
jars.foreach(checkFile(_, "jar"))
val files = tastyFiles ::: jars
inspectFiles(dependenciesClasspath, files)(inspector)
files.nonEmpty && inspectFiles(dependenciesClasspath, files)

/** Load and process TASTy files using TASTy reflect and provided context
*
* Used in doctool to reuse reporter and setup provided by sbt
*
* @param classes List of paths of `.tasty` and `.jar` files (no validation is performed)
* @param classpath Classpath with extra dependencies needed to load class in the `.tasty` files
*/
protected[inspector] def inspectFilesInContext(classpath: List[String], classes: List[String])(using Context): Unit =
if (classes.isEmpty) report.error("Parameter classes should no be empty")
inspectorDriver().process(inspectorArgs(classpath, classes), summon[Context])


private def inspectorDriver(inspector: Inspector) =
private def inspectorDriver() =
class InspectorDriver extends Driver:
override protected def newCompiler(implicit ctx: Context): Compiler = new TastyFromClass

class TastyInspectorPhase extends Phase:
override def phaseName: String = "tastyInspector"

override def runOn(units: List[CompilationUnit])(using ctx0: Context): List[CompilationUnit] =
val ctx = QuotesCache.init(ctx0.fresh)
runOnImpl(units)(using ctx)

private def runOnImpl(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
val quotesImpl = QuotesImpl()
class TastyImpl(val path: String, val ast: quotesImpl.reflect.Tree) extends Tasty[quotesImpl.type] {
val quotes = quotesImpl
}
val tastys = units.map(unit => new TastyImpl(unit.source.path , unit.tpdTree.asInstanceOf[quotesImpl.reflect.Tree]))
inspector.inspect(using quotesImpl)(tastys)
override def run(implicit ctx: Context): Unit =
val qctx = QuotesImpl()
self.processCompilationUnit(using qctx)(ctx.compilationUnit.tpdTree.asInstanceOf[qctx.reflect.Tree])

class TastyInspectorFinishPhase extends Phase:
override def phaseName: String = "tastyInspectorFinish"

override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
val qctx = QuotesImpl()
self.postProcess(using qctx)
units

override def run(implicit ctx: Context): Unit = unsupported("run")
end TastyInspectorPhase

class TastyFromClass extends TASTYCompiler:

Expand All @@ -96,6 +105,7 @@ object TastyInspector:

override protected def backendPhases: List[List[Phase]] =
List(new TastyInspectorPhase) :: // Perform a callback for each compilation unit
List(new TastyInspectorFinishPhase) :: // Perform a final callback
Nil

override def newRun(implicit ctx: Context): Run =
Expand All @@ -113,14 +123,14 @@ object TastyInspector:
("-from-tasty" :: "-Yretain-trees" :: "-classpath" :: fullClasspath :: classes).toArray


private def inspectFiles(classpath: List[String], classes: List[String])(inspector: Inspector): Boolean =
classes match
case Nil => true
case _ =>
val reporter = inspectorDriver(inspector).process(inspectorArgs(classpath, classes))
!reporter.hasErrors
private def inspectFiles(classpath: List[String], classes: List[String]): Boolean =
if (classes.isEmpty)
throw new IllegalArgumentException("Parameter classes should no be empty")

val reporter = inspectorDriver().process(inspectorArgs(classpath, classes))
reporter.hasErrors

end inspectFiles


end TastyInspector
end OldTastyInspector
20 changes: 0 additions & 20 deletions scaladoc/src/scala/tasty/inspector/Tasty.scala

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dotty.tools.scaladoc
package tasty.comments

import scala.quoted.*
import scala.quoted.Quotes

import org.junit.{Test, Rule}
import org.junit.Assert.{assertSame, assertTrue}
Expand Down Expand Up @@ -198,11 +198,14 @@ class MemberLookupTests {

@Test
def test(): Unit = {
import scala.tasty.inspector.*
class MyInspector extends Inspector:
import scala.tasty.inspector.OldTastyInspector
class Inspector extends OldTastyInspector:
var alreadyRan: Boolean = false

def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
this.test()
override def processCompilationUnit(using ctx: quoted.Quotes)(root: ctx.reflect.Tree): Unit =
if !alreadyRan then
this.test()
alreadyRan = true

def test()(using q: Quotes): Unit = {
import dotty.tools.scaladoc.tasty.comments.MemberLookup
Expand All @@ -212,6 +215,6 @@ class MemberLookupTests {
cases.testAll()
}

TastyInspector.inspectTastyFiles(TestUtils.listOurClasses())(new MyInspector)
Inspector().inspectTastyFiles(TestUtils.listOurClasses())
}
}
Loading