Skip to content
Open
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
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class CompilationUnit protected (val source: SourceFile, val info: CompilationUn
def isJava: Boolean = source.ext.isJava

/** Is this the compilation unit of a Java file, or TASTy derived from a Java file */
def typedAsJava =
def typedAsJava: Boolean =
val ext = source.ext
ext.isJava || ext.isTasty && tastyInfo.exists(_.attributes.isJava)

Expand Down Expand Up @@ -150,7 +150,7 @@ object CompilationUnit {
def apply(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit =
val compilationUnitInfo = clsd.symbol.compilationUnitInfo.nn
val file = compilationUnitInfo.associatedFile
apply(SourceFile(file, Codec(ctx.settings.encoding.value)), unpickled, forceTrees, compilationUnitInfo)
apply(SourceFile(file, ctx.settings.sourceroot.value, Codec(ctx.settings.encoding.value)), unpickled, forceTrees, compilationUnitInfo)

/** Make a compilation unit, given picked bytes and unpickled tree */
def apply(source: SourceFile, unpickled: Tree, forceTrees: Boolean, info: CompilationUnitInfo)(using Context): CompilationUnit = {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ trait CommonScalaSettings:
val javabootclasspath: Setting[String] = PathSetting(RootSetting, "javabootclasspath", "Override java boot classpath.", Defaults.javaBootClassPath, aliases = List("--java-boot-class-path"))
val javaextdirs: Setting[String] = PathSetting(RootSetting, "javaextdirs", "Override java extdirs classpath.", Defaults.javaExtDirs, aliases = List("--java-extension-directories"))
val sourcepath: Setting[String] = PathSetting(RootSetting, "sourcepath", "Specify location(s) of source files.", Defaults.scalaSourcePath, aliases = List("--source-path"))
val sourceroot: Setting[String] = PathSetting(RootSetting, "sourceroot", "Specify workspace root directory.", ".")
val sourceroot: Setting[AbstractFile] = FileContainerSetting(RootSetting, "sourceroot", allowsJar = false, "Specify workspace root directory.", new PlainDirectory(Directory(".")))

@SolalPirelli SolalPirelli Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I wanted to reuse the "setting for an AbstractFile", it had to be renamed as this isn't an output. (Better name suggestion than FileContainer for "thing that can contain files, like a directory or a JAR", welcome, though)


val classpath: Setting[String] = PathSetting(RootSetting, "classpath", "Specify where to find user class files.", ScalaSettingsProperties.defaultClasspath, aliases = List("-cp", "--class-path"))
val outputDir: Setting[AbstractFile] = OutputSetting(RootSetting, "d", "directory|jar", "Destination for generated classfiles.", new PlainDirectory(Directory(".")))
val outputDir: Setting[AbstractFile] = FileContainerSetting(RootSetting, "d", allowsJar = true, "Destination for generated classfiles.", new PlainDirectory(Directory(".")))
val color: Setting[String] = ChoiceSetting(RootSetting, "color", "mode", "Colored output", List("always", "never"/*, "auto"*/), "always"/* "auto"*/, aliases = List("--color"))
val verbose: Setting[Boolean] = BooleanSetting(RootSetting, "verbose", "Output messages about what the compiler is doing.", aliases = List("--verbose"))
val version: Setting[Boolean] = BooleanSetting(RootSetting, "version", "Print product version and exit.", aliases = List("--version"))
Expand Down Expand Up @@ -468,7 +468,7 @@ private sealed trait XSettings:

/** Pipeline compilation options */
val XjavaTasty: Setting[Boolean] = BooleanSetting(AdvancedSetting, "Xjava-tasty", "Pickler phase should compute TASTy for .java defined symbols for use by build tools", aliases = List("-Xpickle-java", "-Yjava-tasty", "-Ypickle-java"), preferPrevious = true)
val XearlyTastyOutput: Setting[Option[AbstractFile]] = OptionalOutputSetting(AdvancedSetting, "Xearly-tasty-output", "directory|jar", "Destination to write generated .tasty files to for use in pipelined compilation.", aliases = List("-Xpickle-write", "-Yearly-tasty-output", "-Ypickle-write"), ignoreInvalidArgs = true, preferPrevious = true)
val XearlyTastyOutput: Setting[Option[AbstractFile]] = OptionalFileContainerSetting(AdvancedSetting, "Xearly-tasty-output", allowsJar = true, "Destination to write generated .tasty files to for use in pipelined compilation.", aliases = List("-Xpickle-write", "-Yearly-tasty-output", "-Ypickle-write"), ignoreInvalidArgs = true, preferPrevious = true)
val XallowOutlineFromTasty: Setting[Boolean] = BooleanSetting(AdvancedSetting, "Xallow-outline-from-tasty", "Allow outline TASTy to be loaded with the -from-tasty option.", aliases = List("-Yallow-outline-from-tasty"))

val XmixinForceForwarders = ChoiceSetting(
Expand Down
30 changes: 15 additions & 15 deletions compiler/src/dotty/tools/dotc/config/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ object Settings:
private val StringTag: ClassTag[String] = ClassTag(classOf[String])
private val ListTag: ClassTag[List[?]] = ClassTag(classOf[List[?]])
private val VersionTag: ClassTag[ScalaVersion] = ClassTag(classOf[ScalaVersion])
private val OutputTag: ClassTag[AbstractFile] = ClassTag(classOf[AbstractFile])
private val OptionalOutputTag: ClassTag[Option[AbstractFile]] = ClassTag(classOf[Option[AbstractFile]])
private val FileContainerTag: ClassTag[AbstractFile] = ClassTag(classOf[AbstractFile])
private val OptionalFileContainerTag: ClassTag[Option[AbstractFile]] = ClassTag(classOf[Option[AbstractFile]])

trait SettingCategory:
def prefixLetter: String
Expand Down Expand Up @@ -82,7 +82,7 @@ object Settings:
private def validateSettingString(name: String): Unit =
assert(settingCharacters.matches(name), s"Setting string $name contains invalid characters")

private val validTags = List(BooleanTag, IntTag, StringTag, ListTag, VersionTag, OutputTag, OptionalOutputTag)
private val validTags = List(BooleanTag, IntTag, StringTag, ListTag, VersionTag, FileContainerTag, OptionalFileContainerTag)
private def validateSettingTag(ct: ClassTag[?]): Unit =
assert(validTags.contains(ct), s"Unsupported option value $ct")

Expand Down Expand Up @@ -236,17 +236,17 @@ object Settings:
.getOrElse:
state.fail(s"$argValue is not an integer argument for $name", args)

def setOutput(arg: String, args: List[String], optional: Boolean)(using ArgsSummary) =
def setFileContainer(arg: String, args: List[String], optional: Boolean)(using ArgsSummary) =
val path = Directory(arg)
val isJar = path.ext.isJar
if !isJar && !path.isDirectory then
state.fail(s"'$arg' does not exist or is not a directory or .jar file", args)
state.fail(s"'$arg' does not exist or is not a " + helpArg, args)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only logic change of the settings part -- now if it's just a dir we don't say "directory or .jar file", just "directory"

else
/* Side effect, do not change this method to evaluate eagerly */
def output = if (isJar) JarArchive.create(path) else new PlainDirectory(path)
def fullOutput = if optional then Some(output) else output
val dubious = changed && fullOutput != valueIn(sstate)
val updated = update(fullOutput, arg, args)
def file = if (isJar) JarArchive.create(path) else new PlainDirectory(path)
def fullFile = if optional then Some(file) else file
val dubious = changed && fullFile != valueIn(sstate)
val updated = update(fullFile, arg, args)
if dubious then updated.warn(s"Option $name was updated") else updated

// argRest is the remainder of -foo:bar if any. This setting will receive a value from argRest or args.head.
Expand Down Expand Up @@ -274,8 +274,8 @@ object Settings:
else ct match
case ListTag => setMultivalue(arg1, args1)
case StringTag => setString(arg1, args1)
case OutputTag => setOutput(arg1, args1, optional = false)
case OptionalOutputTag => setOutput(arg1, args1, optional = true)
case FileContainerTag => setFileContainer(arg1, args1, optional = false)
case OptionalFileContainerTag => setFileContainer(arg1, args1, optional = true)
case IntTag => setInt(arg1, args1)
case VersionTag => setVersion(arg1, args1)
case _ => state.fail(s"unknown $ct", args1)
Expand Down Expand Up @@ -480,11 +480,11 @@ object Settings:
def MultiStringSetting(category: SettingCategory, name: String, helpArg: String, descr: String, default: List[String] = Nil, aliases: List[SettingAlias] = Nil, deprecation: Option[Deprecation] = None): Setting[List[String]] =
publish(Setting(category, prependName(name), descr, default, helpArg, aliases = aliases, deprecation = deprecation))

def OutputSetting(category: SettingCategory, name: String, helpArg: String, descr: String, default: AbstractFile, aliases: List[SettingAlias] = Nil, preferPrevious: Boolean = false, deprecation: Option[Deprecation] = None, ignoreInvalidArgs: Boolean = false): Setting[AbstractFile] =
publish(Setting(category, prependName(name), descr, default, helpArg, aliases = aliases, preferPrevious = preferPrevious, deprecation = deprecation, ignoreInvalidArgs = ignoreInvalidArgs))
def FileContainerSetting(category: SettingCategory, name: String, allowsJar: Boolean, descr: String, default: AbstractFile, aliases: List[SettingAlias] = Nil, preferPrevious: Boolean = false, deprecation: Option[Deprecation] = None, ignoreInvalidArgs: Boolean = false): Setting[AbstractFile] =
publish(Setting(category, prependName(name), descr, default, if allowsJar then "directory or .jar file" else "directory", aliases = aliases, preferPrevious = preferPrevious, deprecation = deprecation, ignoreInvalidArgs = ignoreInvalidArgs))

def OptionalOutputSetting(category: SettingCategory, name: String, helpArg: String, descr: String, aliases: List[SettingAlias] = Nil, preferPrevious: Boolean = false, deprecation: Option[Deprecation] = None, ignoreInvalidArgs: Boolean = false): Setting[Option[AbstractFile]] =
publish(Setting(category, prependName(name), descr, None, helpArg, aliases = aliases, preferPrevious = preferPrevious, deprecation = deprecation, ignoreInvalidArgs = ignoreInvalidArgs))
def OptionalFileContainerSetting(category: SettingCategory, name: String, allowsJar: Boolean, descr: String, aliases: List[SettingAlias] = Nil, preferPrevious: Boolean = false, deprecation: Option[Deprecation] = None, ignoreInvalidArgs: Boolean = false): Setting[Option[AbstractFile]] =
publish(Setting(category, prependName(name), descr, None, if allowsJar then "directory or .jar file" else "directory", aliases = aliases, preferPrevious = preferPrevious, deprecation = deprecation, ignoreInvalidArgs = ignoreInvalidArgs))

def PathSetting(category: SettingCategory, name: String, descr: String, default: String, aliases: List[SettingAlias] = Nil, deprecation: Option[Deprecation] = None): Setting[String] =
publish(Setting(category, prependName(name), descr, default, aliases = aliases, deprecation = deprecation))
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ object Contexts {
/** Sourcefile corresponding to given abstract file, memoized */
def getSource(file: AbstractFile, codec: => Codec = Codec(settings.encoding.value)) = {
util.Stats.record("Context.getSource")
base.sources.getOrElseUpdate(file, SourceFile(file, codec))
base.sources.getOrElseUpdate(file, SourceFile(file, settings.sourceroot.value, codec))
}

/** SourceFile with given path, memoized */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ object PositionPickler:
addrOfTree: TreeToAddr,
treeAnnots: untpd.MemberDef => List[tpd.Tree],
typeAnnots: List[tpd.Tree],
relativePathReference: String,
source: SourceFile,
roots: List[Tree],
buf: TastyBuffer = new TastyBuffer(5000),
Expand Down Expand Up @@ -78,8 +77,7 @@ object PositionPickler:

def pickleSource(source: SourceFile): Unit = {
buf.writeInt(SOURCE)
val relativePath = SourceFile.relativePath(source, relativePathReference)
buf.writeInt(pickler.nameBuffer.nameIndex(relativePath.toTermName).index)
buf.writeInt(pickler.nameBuffer.nameIndex(source.pathRelativeToSourceRoot.toTermName).index)
}

/** True if x's position shouldn't be reconstructed automatically from its initial span
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/coverage/Location.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import dotty.tools.dotc.util.SourceFile
* @param fullClassName fully qualified name of the closest enclosing class
* @param classType "type" of the closest enclosing class: Class, Trait or Object
* @param methodName name of the closest enclosing method
* @param sourcePath absolute path of the source file
* @param sourcePath path of the source file
*/
final case class Location(
packageName: String,
className: String,
fullClassName: String,
classType: String,
methodName: String,
sourcePath: Path
sourcePath: String
)

object Location:
Expand All @@ -46,5 +46,5 @@ object Location:
s"$packageName.$className",
classType,
methodName,
source.jfile.get.toPath.toAbsolutePath
source.path
)
28 changes: 11 additions & 17 deletions compiler/src/dotty/tools/dotc/coverage/Serializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,23 @@ object Serializer:
private val CoverageDataFormatVersion = "3.0"

def coverageFilePath(dataDir: String): Path =
Paths.get(dataDir, CoverageFileName).toAbsolutePath
Paths.get(dataDir, CoverageFileName)

/** Write out coverage data to the given data directory, using the default coverage filename */
def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit =
serialize(coverage, coverageFilePath(dataDir), Paths.get(sourceRoot).toAbsolutePath)
def serialize(coverage: Coverage, dataDir: String): Unit =
serialize(coverage, coverageFilePath(dataDir))

/** Write out coverage data to a file. */
def serialize(coverage: Coverage, file: Path, sourceRoot: Path): Unit =
def serialize(coverage: Coverage, file: Path): Unit =
val writer = Files.newBufferedWriter(file)
try
serialize(coverage, writer, sourceRoot)
serialize(coverage, writer)
finally
writer.close()

/** Write out coverage data (info about each statement that can be covered) to a writer.
*/
def serialize(coverage: Coverage, writer: Writer, sourceRoot: Path): Unit =

def getRelativePath(filePath: Path): String =
// We need to normalize the path here because the relativizing paths containing '.' or '..' differs between Java versions
// https://bugs.openjdk.java.net/browse/JDK-8066943
val relPath = sourceRoot.normalize.relativize(filePath)
relPath.toString
def serialize(coverage: Coverage, writer: Writer): Unit =

def writeHeader(writer: Writer): Unit =
writer.write(s"""# Coverage data, format version: $CoverageDataFormatVersion
Expand Down Expand Up @@ -67,7 +61,7 @@ object Serializer:
def writeStatement(stmt: Statement, writer: Writer): Unit =
// Note: we write 0 for the count because we have not measured the actual coverage at this point
writer.write(s"""${stmt.id}
|${getRelativePath(stmt.location.sourcePath).escaped}
|${stmt.location.sourcePath.escaped}
|${stmt.location.packageName.escaped}
|${stmt.location.className.escaped}
|${stmt.location.classType}
Expand All @@ -90,12 +84,12 @@ object Serializer:
.sortBy(_.id)
.foreach(stmt => writeStatement(stmt, writer))

def deserialize(file: Path, sourceRoot: String): Coverage =
def deserialize(file: Path): Coverage =
val source = Source.fromFile(file.toFile(), UTF_8.name())
try deserialize(source.getLines(), Paths.get(sourceRoot).toAbsolutePath)
try deserialize(source.getLines())
finally source.close()

def deserialize(lines: Iterator[String], sourceRoot: Path): Coverage =
def deserialize(lines: Iterator[String]): Coverage =
def toStatement(lines: Iterator[String]): Statement =
val id: Int = lines.next().toInt
val sourcePath = lines.next()
Expand All @@ -110,7 +104,7 @@ object Serializer:
fullClassName,
classType,
method,
sourceRoot.resolve(sourcePath).normalize()
sourcePath
)
val start: Int = lines.next().toInt
val end: Int = lines.next().toInt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import scala.io.Codec
* the logical package structure of the whole source path.
*/
class LogicalPackagesProvider(sourcePath: String) {

/**
* Parse all source files in the sourcepath and build the logical package structure.
*/
def root(using Context): LogicalPackage =
val pkg: ParsedLogicalPackage = newPackage()
val sourceRoots = allSources(sourcePath).map(f => SourceFile(f, Codec(ctx.settings.encoding.value)))
val sourceRoots = allSources(sourcePath).map(f => SourceFile(f, ctx.settings.sourceroot.value, Codec(ctx.settings.encoding.value)))
for sourceFile <- sourceRoots do
try
parseSourceFile(sourceFile, pkg)
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,7 @@ object PickledQuotes {
treePkl.pickle(tree :: Nil)
treePkl.compactify()
if tree.span.exists then
val reference = ctx.settings.sourceroot.value
PositionPickler.picklePositions(pickler, treePkl.buf.addrOfTree, treePkl.treeAnnots, treePkl.typeAnnots, reference,
PositionPickler.picklePositions(pickler, treePkl.buf.addrOfTree, treePkl.treeAnnots, treePkl.typeAnnots,
ctx.compilationUnit.source, tree :: Nil)

val pickled = pickler.assembleParts()
Expand Down
Loading
Loading