diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 0c3b30adcaa2..2c5ffaaf4967 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -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) @@ -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 = { diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index be15a1f6f427..f83895488b8a 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -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("."))) 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")) @@ -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( diff --git a/compiler/src/dotty/tools/dotc/config/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index e1854e4f1bd5..7f81801a72e2 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -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 @@ -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") @@ -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) 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. @@ -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) @@ -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)) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index b549ed58f2f2..5055f8d83ee1 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -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 */ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala index c316223c1aa7..65ca09ed1aac 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala @@ -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), @@ -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 diff --git a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala index 3c5297334a3b..1193dfa1209d 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala @@ -2,7 +2,6 @@ package dotty.tools.dotc package coverage import scala.collection.mutable -import java.nio.file.Path /** Holds a list of statements to include in the coverage reports. */ class Coverage: diff --git a/compiler/src/dotty/tools/dotc/coverage/Location.scala b/compiler/src/dotty/tools/dotc/coverage/Location.scala index 069fcebc53e3..8f96e4ee27fb 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Location.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Location.scala @@ -4,7 +4,6 @@ package coverage import ast.tpd.* import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Flags.* -import java.nio.file.Path import dotty.tools.dotc.util.SourceFile /** Information about the location of a coverable piece of code. @@ -14,7 +13,7 @@ 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 relative to the source root */ final case class Location( packageName: String, @@ -22,7 +21,7 @@ final case class Location( fullClassName: String, classType: String, methodName: String, - sourcePath: Path + sourcePath: String ) object Location: @@ -46,5 +45,5 @@ object Location: s"$packageName.$className", classType, methodName, - source.jfile.get.toPath.toAbsolutePath + source.pathRelativeToSourceRoot ) diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala index 84392991aef3..a48da7ba98a5 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -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 @@ -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} @@ -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() @@ -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 diff --git a/compiler/src/dotty/tools/dotc/interactive/LogicalPackagesProvider.scala b/compiler/src/dotty/tools/dotc/interactive/LogicalPackagesProvider.scala index ad402750d0ba..beafdd96fe7b 100644 --- a/compiler/src/dotty/tools/dotc/interactive/LogicalPackagesProvider.scala +++ b/compiler/src/dotty/tools/dotc/interactive/LogicalPackagesProvider.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index 3702259d687d..017c6f7f1381 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -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() diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index ec50bee80b11..312381a288dd 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -60,7 +60,6 @@ private[semanticdb] class ExtractSemanticDB private (phaseMode: ExtractSemanticD override def isCheckable: Boolean = false private def computeDiagnostics( - sourceRoot: String, warnings: Map[SourceFile, List[dotty.tools.dotc.reporting.Diagnostic]], append: ((Path, List[Diagnostic])) => Unit)(using Context): Boolean = monitor(phaseName) { val unit = ctx.compilationUnit @@ -68,21 +67,19 @@ private[semanticdb] class ExtractSemanticDB private (phaseMode: ExtractSemanticD val outputDir = ExtractSemanticDB.semanticdbPath( unit.source, - ExtractSemanticDB.semanticdbOutDir, - sourceRoot + ExtractSemanticDB.semanticdbOutDir ) append((outputDir, ws.map(_.toSemanticDiagnostic))) } } - private def extractSemanticDB(sourceRoot: String, writeSemanticdbText: Boolean)(using Context): Boolean = + private def extractSemanticDB(writeSemanticdbText: Boolean)(using Context): Boolean = monitor(phaseName) { val unit = ctx.compilationUnit val outputDir = ExtractSemanticDB.semanticdbPath( unit.source, - ExtractSemanticDB.semanticdbOutDir, - sourceRoot + ExtractSemanticDB.semanticdbOutDir ) val extractor = ExtractSemanticDB.Extractor() extractor.extract(unit.tpdTree) @@ -92,20 +89,18 @@ private[semanticdb] class ExtractSemanticDB private (phaseMode: ExtractSemanticD extractor.symbolInfos.toList, extractor.synthetics.toList, outputDir, - sourceRoot, writeSemanticdbText ) } override def runOn(units: List[CompilationUnit])(using ctx: Context): List[CompilationUnit] = { - val sourceRoot = ctx.settings.sourceroot.value val appendDiagnostics = phaseMode == ExtractSemanticDB.PhaseMode.AppendDiagnostics val unitContexts = units.map(ctx.fresh.setCompilationUnit(_).withRootImports) if (appendDiagnostics) val warningsAndInfos = (ctx.reporter.allWarnings ++ ctx.reporter.allInfos).groupBy(w => w.pos.source) val buf = mutable.ListBuffer.empty[(Path, Seq[Diagnostic])] val units0 = - for unitCtx <- unitContexts if computeDiagnostics(sourceRoot, warningsAndInfos, buf += _)(using unitCtx) + for unitCtx <- unitContexts if computeDiagnostics(warningsAndInfos, buf += _)(using unitCtx) yield unitCtx.compilationUnit cancellable { buf.toList.asJava.parallelStream().forEach { case (out, diagnostics) => @@ -115,7 +110,7 @@ private[semanticdb] class ExtractSemanticDB private (phaseMode: ExtractSemanticD units0 else val writeSemanticdbText = ctx.settings.semanticdbText.value - for unitCtx <- unitContexts if extractSemanticDB(sourceRoot, writeSemanticdbText)(using unitCtx) + for unitCtx <- unitContexts if extractSemanticDB(writeSemanticdbText)(using unitCtx) yield unitCtx.compilationUnit } @@ -159,14 +154,13 @@ private[semanticdb] object ExtractSemanticDB: symbolInfos: List[SymbolInformation], synthetics: List[Synthetic], outpath: Path, - sourceRoot: String, semanticdbText: Boolean ): Unit = Files.createDirectories(outpath.getParent()) val doc: TextDocument = TextDocument( schema = Schema.SEMANTICDB4, language = Language.SCALA, - uri = Tools.mkURIstring(Paths.get(relPath(source, sourceRoot))), + uri = Tools.mkURIstring(Path.of(source.pathRelativeToSourceRoot)), text = if semanticdbText then String(source.content) else "", md5 = internal.MD5.compute(String(source.content)), symbols = symbolInfos, @@ -201,14 +195,11 @@ private[semanticdb] object ExtractSemanticDB: case Success(_) => // success to update semanticdb, say nothing end appendDiagnostics - private def relPath(source: SourceFile, sourceRoot: String) = - SourceFile.relativePath(source, sourceRoot) - - private def semanticdbPath(source: SourceFile, base: Path, sourceRoot: String): Path = + private def semanticdbPath(source: SourceFile, base: Path): Path = absolutePath(base) .resolve("META-INF") .resolve("semanticdb") - .resolve(relPath(source, sourceRoot)) + .resolve(source.pathRelativeToSourceRoot) .resolveSibling(source.name + ".semanticdb") /** Extractor of symbol occurrences from trees */ @@ -389,7 +380,7 @@ private[semanticdb] object ExtractSemanticDB: for arg <- tree.args do arg match case tree @ NamedArg(name, arg) => - traverse(localBodies.get(arg.symbol).getOrElse(arg)) + traverse(localBodies.getOrElse(arg.symbol, arg)) genParamSymbol(name).foreach( registerUse(_, tree.span.startPos.withEnd(tree.span.start + name.toString.length), tree.source) ) diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index adfcec60d2e1..659d7bb729ae 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -165,7 +165,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val coverageFilePath = Serializer.coverageFilePath(outputPath) val previousCoverage = if Files.exists(coverageFilePath) then - Serializer.deserialize(coverageFilePath, ctx.settings.sourceroot.value) + Serializer.deserialize(coverageFilePath) else Coverage() // Initialize coverage patterns once @@ -205,21 +205,21 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: // Serialize once at the end with merged coverage val mergedCoverage = Coverage() - val currentFiles = units.map(_.source.jfile.get.toPath.toAbsolutePath) + val currentFiles = units.map(_.source.pathRelativeToSourceRoot) // Add statements from previous coverage that aren't from recompiled files // and whose source files still exist previousCoverage.statements .filterNot(stmt => val source = stmt.location.sourcePath - currentFiles.contains(source) || !Files.exists(source) + currentFiles.contains(source) || !Files.exists(Path.of(ctx.settings.sourceroot.value.path).resolve(source)) ) .foreach(mergedCoverage.addStatement) // Add all new statements from this compilation ctx.base.coverage.nn.statements.foreach(mergedCoverage.addStatement) - Serializer.serialize(mergedCoverage, outputPath, ctx.settings.sourceroot.value) + Serializer.serialize(mergedCoverage, outputPath) result @@ -328,7 +328,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: else if erasedArgs.isEmpty then transform(trees) else trees.lazyZip(erasedArgs).map { (arg, isErased) => if isErased then arg else transform(arg) - }.toList + } private def transformInnerApply(tree: Tree)(using Context): Tree = tree match case a: Apply if a.fun.symbol == defn.StringContextModule_apply => diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index ba2a628ed176..f0a1bc4c4e96 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -379,12 +379,12 @@ class Pickler extends Phase { // This can be called inside a Future in a background thread, it must not capture a Context def computePickled(pickler: TastyPickler, treePkl: TreePickler, tree: Tree, unit: CompilationUnit, internalName: String, attributes: Attributes, - reference: String/*ctx.settings.sourceroot.value*/, dropComments: Boolean/*ctx.settings.XdropComments.value*/): Array[Byte] = + dropComments: Boolean/*ctx.settings.XdropComments.value*/): Array[Byte] = serialized.run { scratch => treePkl.compactify(scratch) if tree.span.exists then PositionPickler.picklePositions( - pickler, treePkl.buf.addrOfTree, treePkl.treeAnnots, treePkl.typeAnnots, reference, + pickler, treePkl.buf.addrOfTree, treePkl.treeAnnots, treePkl.typeAnnots, unit.source, tree :: Nil, scratch.positionBuffer, scratch.pickledIndices) @@ -430,16 +430,13 @@ class Pickler extends Phase { if ctx.settings.YtestPickler.value then beforePickling(cls) = tree.show(using printerContext(unit.typedAsJava)) - val sourceRelativePath = - val reference = ctx.settings.sourceroot.value - util.SourceFile.relativePath(unit.source, reference) val isJavaAttr = unit.isJava // we must always set JAVAattr when pickling Java sources if isJavaAttr then // assert that Java sources didn't reach Pickler without `-Xjava-tasty`. assert(ctx.settings.XjavaTasty.value, "unexpected Java source file without -Xjava-tasty") val isOutline = isJavaAttr // TODO: later we may want outline for Scala sources too val attributes = Attributes( - sourceFile = sourceRelativePath, + sourceFile = unit.source.pathRelativeToSourceRoot, scala2StandardLibrary = Feature.shouldBehaveAsScala2, explicitNulls = ctx.settings.YexplicitNulls.value, captureChecked = Feature.ccEnabled, @@ -463,11 +460,10 @@ class Pickler extends Phase { val internalName = if fastDoAsyncTasty then computeInternalName(cls) else "" if successful then - val sourceroot = ctx.settings.sourceroot.value val dropComments = ctx.settings.XdropComments.value // must not depend on a Context as it's passed to the executor, so we fetch settings before def doComputePickled() = - computePickled(pickler, treePkl, tree, unit, internalName, attributes, sourceroot, dropComments) + computePickled(pickler, treePkl, tree, unit, internalName, attributes, dropComments) /** A function that returns the pickled bytes. Depending on `Pickler.ParallelPickling` * either computes the pickled data in a future or eagerly before constructing the * function value. diff --git a/compiler/src/dotty/tools/dotc/util/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index 311f76438660..ba2be54eee4e 100644 --- a/compiler/src/dotty/tools/dotc/util/SourceFile.scala +++ b/compiler/src/dotty/tools/dotc/util/SourceFile.scala @@ -9,15 +9,16 @@ import core.Decorators.* import scala.io.Codec import Chars.* + import scala.annotation.internal.sharable import scala.collection.mutable.ArrayBuffer import scala.compiletime.uninitialized - import java.io.File.separator import java.net.URI import java.nio.charset.StandardCharsets import java.nio.file.{FileSystemException, Paths} import java.util.Optional +import scala.annotation.threadUnsafe object WrappedSourceFile: enum MagicHeaderInfo: @@ -60,7 +61,7 @@ object WrappedSourceFile: result case result => result -class SourceFile (val file: AbstractFile | Null, codec: Codec) extends interfaces.SourceFile { +class SourceFile (val file: AbstractFile | Null, sourceRoot: AbstractFile, codec: Codec) extends interfaces.SourceFile { private var myContent: Array[Char] | Null = null /** The contents of the original source file. Note that this can be empty, for example when @@ -79,6 +80,28 @@ class SourceFile (val file: AbstractFile | Null, codec: Codec) extends interface if file eq null then FileExtension.Empty else file.ext override def path: String = if file eq null then "" else file.path + @threadUnsafe lazy val pathRelativeToSourceRoot: String = + if (file eq null) || (file.jpath eq null) then + throw new AssertionError(s"pathRelativeToSourceRoot called on a missing or non-disk file ('$path')") + else if sourceRoot.jpath eq null then + file.path + else + val sourcePath = file.jpath.nn.toAbsolutePath.normalize + val refPath = sourceRoot.jpath.nn.toAbsolutePath.normalize + if sourcePath.startsWith(refPath) then + // On Windows we can only relativize paths if root component matches: + // try refPath.relativize(sourcePath).toString + // catch case _: IllegalArgumentException => sourcePath.toString + // As we already check that the prefix matches, the special handling for + // Windows is not needed. + // + // Also, consistently use '/' as separator so any path loaded from anywhere + // is guaranteed to have the same separator, otherwise we'd see, e.g., "a\path", + // and wonder "is this a Windows 2-part path, or a non-Windows file name with a backslash in it?" + refPath.relativize(sourcePath).toString.replace(java.io.File.separatorChar, '/') + else + file.path + override def jfile: Optional[JFile] = if file eq null then Optional.empty() else file.jfile @@ -131,7 +154,7 @@ class SourceFile (val file: AbstractFile | Null, codec: Codec) extends interface lineIndicesCache = calculateLineIndicesFromContents() lineIndicesCache - def initialized = lineIndicesCache != null + def initialized: Boolean = lineIndicesCache != null def setLineIndicesFromLineSizes(sizes: Array[Int]): Unit = val lines = sizes.length @@ -182,7 +205,7 @@ class SourceFile (val file: AbstractFile | Null, codec: Codec) extends interface /** The column corresponding to `offset`, starting at 0 */ def column(offset: Int): Int = { - var idx = startOfLine(offset) + val idx = startOfLine(offset) offset - idx } @@ -207,51 +230,15 @@ object SourceFile { * with the local separator converted to "/". The last element of the path will be the simple name of the file. */ def virtual(name: String, content: String) = - new SourceFile(new VirtualFile(name.replace(separator, "/"), content.getBytes(StandardCharsets.UTF_8)), Codec.UTF8) + new SourceFile(new VirtualFile(name.replace(separator, "/"), content.getBytes(StandardCharsets.UTF_8)), new VirtualFile("_root_", Array.emptyByteArray), Codec.UTF8) /** A helper method to create a virtual source file for given URI. */ def virtual(uri: URI, content: String): SourceFile = virtual(java.nio.file.Path.of(uri).toString, content) - - /** Returns the relative path of `source` within the `reference` path - * - * It returns the current path under `source.file.jpath` if it is not contained in `reference`. - */ - def relativePath(source: SourceFile, reference: String): String = { - val file = source.file - val jpath = if file == null then null else file.jpath - if jpath eq null then - "" // repl and other custom tests use abstract files with no path - else - val sourcePath = jpath.toAbsolutePath.normalize - val refPath = java.nio.file.Paths.get(reference).toAbsolutePath.normalize - - if sourcePath.startsWith(refPath) then - // On Windows we can only relativize paths if root component matches - // (see implementation of sun.nio.fs.WindowsPath#relativize) - // - // try refPath.relativize(sourcePath).toString - // catch case _: IllegalArgumentException => sourcePath.toString - // - // As we already check that the prefix matches, the special handling for - // Windows is not needed. - - // We also consistently use forward slashes as path element separators - // for relative paths. If we didn't do that, it'd be impossible to parse - // them back, as one would need to know whether they were created on Windows - // and use both slashes as separators, or on other OS and use forward slash - // as separator, backslash as file name character. - - import scala.jdk.CollectionConverters.* - val path = refPath.relativize(sourcePath) - path.iterator.asScala.mkString("/") - else - jpath.toString - } } -@sharable object NoSource extends SourceFile(null, Codec.UTF8) { +@sharable object NoSource extends SourceFile(null, new VirtualFile("_root_", Array.emptyByteArray), Codec.UTF8) { override def exists: Boolean = false override def atSpan(span: Span): SourcePosition = NoSourcePosition } diff --git a/compiler/test/dotty/tools/dotc/CoverageSupport.scala b/compiler/test/dotty/tools/dotc/CoverageSupport.scala index 0e8ff256b6af..d45c4102d656 100644 --- a/compiler/test/dotty/tools/dotc/CoverageSupport.scala +++ b/compiler/test/dotty/tools/dotc/CoverageSupport.scala @@ -97,8 +97,7 @@ trait CoverageSupport: assert(Files.size(coverageFile) > 0, s"Coverage file is empty: $coverageFile for test ${testSource.title}") // Verify file can be deserialized (valid format) - val sourceRoot = Paths.get(".").toAbsolutePath.toString - assert(Try(Serializer.deserialize(coverageFile, sourceRoot)).isSuccess, s"Coverage file has invalid format: $coverageFile for test ${testSource.title}") + assert(Try(Serializer.deserialize(coverageFile)).isSuccess, s"Coverage file has invalid format: $coverageFile for test ${testSource.title}") finally // Cleanup temporary directory even if exceptions are thrown try diff --git a/compiler/test/dotty/tools/dotc/ScalaCommandTest.scala b/compiler/test/dotty/tools/dotc/ScalaCommandTest.scala index 932dbc81097a..4c4870271de3 100644 --- a/compiler/test/dotty/tools/dotc/ScalaCommandTest.scala +++ b/compiler/test/dotty/tools/dotc/ScalaCommandTest.scala @@ -26,15 +26,16 @@ class ScalaCommandTest: @Test def `Unfold @file`: Unit = inContext { val settings = config.ScalaSettings val file = temporaryFolder.newFile("config") + val sourceRoot = temporaryFolder.newFolder("src") val writer = java.io.FileWriter(file); - writer.write("-sourceroot myNewRoot someMoreFiles"); + writer.write(s"-sourceroot $sourceRoot someMoreFiles"); writer.close(); val args = s"-cp path/to/classes1:other/path/to/classes2 @${file} someFiles".split(" ") val summary = ScalacCommand.distill(args, settings)() given SettingsState = summary.sstate assertEquals("path/to/classes1:other/path/to/classes2", settings.classpath.value) - assertEquals("myNewRoot", settings.sourceroot.value) + assertEquals(sourceRoot.toString, settings.sourceroot.value.path) assertEquals("someMoreFiles" :: "someFiles" :: Nil, summary.arguments) } diff --git a/compiler/test/dotty/tools/dotc/SettingsTests.scala b/compiler/test/dotty/tools/dotc/SettingsTests.scala index fd5ba3a930a4..3ca6ec216496 100644 --- a/compiler/test/dotty/tools/dotc/SettingsTests.scala +++ b/compiler/test/dotty/tools/dotc/SettingsTests.scala @@ -252,7 +252,7 @@ class SettingsTests: @Test def `dir option also warns`: Unit = object Settings extends SettingGroup: - val option = OutputSetting(RootSetting, "option", "out", "A file", Paths.get("a", "b", "c").toPlainFile) + val option = FileContainerSetting(RootSetting, "option", false, "A file", Paths.get("a", "b", "c").toPlainFile) Using.resource(createTempDirectory("i13887")) { dir => val target = createDirectory(dir.resolve("x")) val mistake = createDirectory(dir.resolve("y")) @@ -297,7 +297,7 @@ class SettingsTests: val result = Using.resource(Files.createTempFile("myfile", ".jar")): file => object Settings extends SettingGroup: val defaultDir = new PlainDirectory(Directory(".")) - val testOutput = OutputSetting(RootSetting, "testOutput", "testOutput", "", defaultDir) + val testOutput = FileContainerSetting(RootSetting, "testOutput", true, "", defaultDir) import Settings.* Files.write(file, "test".getBytes()) @@ -313,7 +313,7 @@ class SettingsTests: ): (file1, file2) => object Settings extends SettingGroup: val defaultDir = new PlainDirectory(Directory(".")) - val testOutput = OutputSetting(RootSetting, "testOutput", "testOutput", "", defaultDir, preferPrevious = true) + val testOutput = FileContainerSetting(RootSetting, "testOutput", true, "", defaultDir, preferPrevious = true) import Settings.* @@ -336,7 +336,7 @@ class SettingsTests: val result = Using.resource(Files.createTempFile("myfile", ".jar")): file => object Settings extends SettingGroup: val defaultDir = new PlainDirectory(Directory(".")) - val testOutput = OutputSetting(RootSetting, "testOutput", "testOutput", "", defaultDir, preferPrevious = true, deprecation = Deprecation.renamed("XtestOutput")) + val testOutput = FileContainerSetting(RootSetting, "testOutput", true, "", defaultDir, preferPrevious = true, deprecation = Deprecation.renamed("XtestOutput")) import Settings.* @@ -359,7 +359,7 @@ class SettingsTests: val intSetting = IntSetting(RootSetting, "intSetting", "intSetting", 0) val intChoiceSetting = IntChoiceSetting(RootSetting, "intChoiceSetting", "intChoiceSetting", List(1,2,3), 1) val multiStringSetting = MultiStringSetting(RootSetting, "multiStringSetting", "multiStringSetting", Help, default = List("a", "b")) - val outputSetting = OutputSetting(RootSetting, "outputSetting", "outputSetting", Help, new PlainDirectory(Directory("."))) + val outputSetting = FileContainerSetting(RootSetting, "outputSetting", true, Help, new PlainDirectory(Directory("."))) val pathSetting = PathSetting(RootSetting, "pathSetting", "pathSetting", ".") val phasesSetting = PhasesSetting(RootSetting, "phasesSetting", "phasesSetting", "all") val versionSetting= VersionSetting(RootSetting, "versionSetting", "versionSetting") @@ -473,7 +473,7 @@ class SettingsTests: object Settings extends SettingGroup: val foo = BooleanSetting(RootSetting, "foo", "foo", ignoreInvalidArgs = true, preferPrevious = true) val bar = BooleanSetting(RootSetting, "bar", "bar") - val baz = OutputSetting(RootSetting, "out", "dir", "A file", default = Paths.get("out", "baz").toPlainFile, + val baz = FileContainerSetting(RootSetting, "out", false, "A file", default = Paths.get("out", "baz").toPlainFile, ignoreInvalidArgs = true, preferPrevious = true) import Settings.* Using.resource(createTempDirectory("testDir")): dir => diff --git a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala index 5a252081fff2..3c694830ebfc 100644 --- a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala +++ b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala @@ -11,7 +11,7 @@ import dotty.tools.vulpix.TestConfiguration import org.junit.Test import org.junit.Assert.* import core.Decorators.toMessage -import dotty.tools.io.{Path, PlainFile} +import dotty.tools.io.* import java.net.URI import java.nio.file.Files @@ -200,7 +200,7 @@ class ScalaSettingsTests: warning = reporting.Diagnostic.Warning( "A warning".toMessage, util.SourcePosition( - source = util.SourceFile(new PlainFile(Path(file)), Codec.UTF8), + source = util.SourceFile(new PlainFile(Path(file)), new PlainDirectory(Directory(".")), Codec.UTF8), span = util.Spans.Span(1L) ) ) @@ -215,7 +215,7 @@ class ScalaSettingsTests: warning = reporting.Diagnostic.Warning( "A warning".toMessage, util.SourcePosition( - source = util.SourceFile(new PlainFile(Path(file)), Codec.UTF8), + source = util.SourceFile(new PlainFile(Path(file)), new PlainDirectory(Directory(".")), Codec.UTF8), span = util.Spans.Span(1L) ) ) diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index 1537ef4703fa..d0cc208b7af5 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -58,7 +58,7 @@ class CoverageTests: // as these are generated at runtime by the scala.runtime.coverage.Invoker val (targetDir, expectFile, expectMeasurementFile) = if Files.isDirectory(path) then - val dirName = path.getFileName().toString + val dirName = path.getFileName.toString assert(!Files.walk(path).filter(scalaFile.matches(_)).toArray.isEmpty, s"No scala files found in test directory: ${path}") val targetDir = computeCoverageInTmp(path, isDirectory = true, dir, run) (targetDir, path.resolve(s"test.scoverage.check"), path.resolve(s"test.measurement.check")) @@ -129,7 +129,7 @@ class CoverageTests: private def findMeasurementFile(targetDir: Path): Path = { val allFilesInTarget = Files.list(targetDir).collect(Collectors.toList).asScala - allFilesInTarget.filter(_.getFileName.toString.startsWith("scoverage.measurements.")).headOption.getOrElse( + allFilesInTarget.find(_.getFileName.toString.startsWith("scoverage.measurements.")).getOrElse( throw new AssertionError(s"Expected to find measurement file in targetDir [${targetDir}] but none were found.") ) } @@ -151,8 +151,8 @@ class CoverageTests: assert(Files.exists(scoverageFile), s"Expected scoverage file to exist at $scoverageFile") locally { - val coverage = Serializer.deserialize(scoverageFile, sourceRoot.toString()) - val filesWithCoverage = coverage.statements.map(_.location.sourcePath.getFileName.toString).toSet + val coverage = Serializer.deserialize(scoverageFile) + val filesWithCoverage = coverage.statements.map(s => Path.of(s.location.sourcePath).getFileName.toString).toSet assertEquals(Set("file1.scala"), filesWithCoverage) } @@ -161,8 +161,8 @@ class CoverageTests: compileFile(sourceFile2.toString, options).checkCompile() locally { - val coverage = Serializer.deserialize(scoverageFile, sourceRoot.toString()) - val filesWithCoverage = coverage.statements.map(_.location.sourcePath.getFileName.toString).toSet + val coverage = Serializer.deserialize(scoverageFile) + val filesWithCoverage = coverage.statements.map(s => Path.of(s.location.sourcePath).getFileName.toString).toSet assertEquals(Set("file1.scala", "file2.scala"), filesWithCoverage) } @@ -183,8 +183,8 @@ class CoverageTests: assert(Files.exists(scoverageFile), s"Expected scoverage file to exist at $scoverageFile") locally { - val coverage = Serializer.deserialize(scoverageFile, sourceRoot.toString()) - val filesWithCoverage = coverage.statements.map(_.location.sourcePath.getFileName.toString).toSet + val coverage = Serializer.deserialize(scoverageFile) + val filesWithCoverage = coverage.statements.map(s => Path.of(s.location.sourcePath).getFileName.toString).toSet assertEquals(Set("file1.scala"), filesWithCoverage) } @@ -195,8 +195,8 @@ class CoverageTests: compileFile(sourceFile2.toString, options).checkCompile() locally { - val coverage = Serializer.deserialize(scoverageFile, sourceRoot.toString()) - val filesWithCoverage = coverage.statements.map(_.location.sourcePath.getFileName.toString).toSet + val coverage = Serializer.deserialize(scoverageFile) + val filesWithCoverage = coverage.statements.map(s => Path.of(s.location.sourcePath).getFileName.toString).toSet assertEquals(Set("file2.scala"), filesWithCoverage) } diff --git a/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala b/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala index 294008a0c46f..625eb73fea24 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala @@ -21,7 +21,7 @@ class ParserTest extends DottyTest { parsedTrees.clear() } - def parse(file: PlainFile): Tree = parseSource(SourceFile(file, Codec.UTF8)) + def parse(file: PlainFile): Tree = parseSource(SourceFile(file, new PlainDirectory(Directory(".")), Codec.UTF8)) private def parseSource(source: SourceFile): Tree = { //println("***** parsing " + source.file) diff --git a/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala b/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala index 120370631a49..cdc3adec922c 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala @@ -19,7 +19,7 @@ class ScannerTest extends DottyTest { def scan(file: PlainFile): Unit = { //println("***** scanning " + file) - val source = SourceFile(file, Codec.UTF8) + val source = SourceFile(file, new PlainDirectory(Directory(".")), Codec.UTF8) val scanner = new Scanner(source) var i = 0 while (scanner.token != EOF) { diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 12497af6bf47..d9bae38e286b 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -2,20 +2,20 @@ package dotty package tools package vulpix -import java.io.{File as JFile, PrintStream} +import java.io.{PrintStream, File as JFile} import java.lang.management.ManagementFactory import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.nio.file.{Files, NoSuchFileException, Paths} import java.nio.charset.{Charset, StandardCharsets} import java.util.{HashMap, Timer, TimerTask} -import java.util.concurrent.{TimeUnit, TimeoutException, Executors => JExecutors} - -import scala.collection.mutable, mutable.ArrayBuffer, mutable.ListBuffer +import java.util.concurrent.{TimeUnit, TimeoutException, Executors as JExecutors} +import scala.collection.mutable +import mutable.ArrayBuffer +import mutable.ListBuffer import scala.io.{Codec, Source} import scala.jdk.CollectionConverters.* import scala.util.{Random, Try, Using} import scala.util.Properties.{isJavaAtLeast, javaSpecVersion} - import dotc.{Compiler, Driver} import dotty.tools.dotc.CoverageSupport import dotc.core.Contexts.* @@ -23,8 +23,8 @@ import dotc.report import dotc.interfaces.Diagnostic.{ERROR, WARNING} import dotc.reporting.{Reporter, TestReporter} import dotc.reporting.Diagnostic -import dotc.util.{SourceFile, SourcePosition, Spans, NoSourcePosition} -import io.AbstractFile +import dotc.util.{NoSourcePosition, SourceFile, SourcePosition, Spans} +import io.{AbstractFile, Directory, PlainDirectory} import util.chaining.* /** A parallel testing suite whose goal is to integrate nicely with JUnit @@ -632,7 +632,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport: val lineNum = line.nn.toInt val columnNum = column.nn.toInt val abstractFile = AbstractFile.getFile(filePath.nn).nn - val sourceFile = SourceFile(abstractFile, Codec.UTF8) + val sourceFile = SourceFile(abstractFile, new PlainDirectory(Directory(".")), Codec.UTF8) val offset = sourceFile.lineToOffset(lineNum - 1) + columnNum - 1 val span = Spans.Span(offset) val sourcePos = SourcePosition(sourceFile, span) diff --git a/project/scripts/checkErrorCodeSnippets.scala b/project/scripts/checkErrorCodeSnippets.scala index 07238dadb990..95739ab539dc 100644 --- a/project/scripts/checkErrorCodeSnippets.scala +++ b/project/scripts/checkErrorCodeSnippets.scala @@ -641,8 +641,7 @@ object SnippetCompiler: val reporter = new StoreReporter(null) with UniqueMessagePositions with HideNonSensicalMessages // Create virtual source file - val virtualFile = new VirtualFile("snippet.scala", code.getBytes("UTF-8")) - val sourceFile = dotty.tools.dotc.util.SourceFile(virtualFile, scala.io.Codec.UTF8) + val sourceFile = dotty.tools.dotc.util.SourceFile.virtual("snippet.scala", code) // Process all options val allOpts = baseOpts ++ List("-d", outputDir.toString) ++ extraOpts diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 8057f93fc047..531024c05f07 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -19,6 +19,7 @@ import liqp.TemplateContext import liqp.tags.Tag import liqp.nodes.LNode import scala.jdk.CollectionConverters._ +import dotty.tools.io.{Directory, PlainDirectory} import scala.io.Source import dotty.tools.scaladoc.snippets._ @@ -78,7 +79,7 @@ case class TemplateFile( lazy val snippetCheckingFunc: SnippetChecker.SnippetCheckingFunc = val path = Some(Paths.get(file.getAbsolutePath)) val pathBasedArg = ssctx.snippetCompilerArgs.get(path) - val sourceFile = dotty.tools.dotc.util.SourceFile(dotty.tools.io.AbstractFile.getFile(path.get), scala.io.Codec.UTF8) + val sourceFile = dotty.tools.dotc.util.SourceFile(dotty.tools.io.AbstractFile.getFile(path.get), new PlainDirectory(Directory(".")), scala.io.Codec.UTF8) (snippet: SnippetSource, argOverride: Option[SnippetCompilerArg]) => val arg = argOverride.fold(pathBasedArg)(pathBasedArg.merge(_)) val compilerData = SnippetCompilerData("staticsitesnippet", SnippetCompilerData.Position(configOffset - 1, 0)) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala index bef91c2409b5..4ebec34e9ae0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala @@ -94,7 +94,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) { private given qctx.type = qctx private lazy val srcPos = if owner == qctx.reflect.defn.RootClass then { - val sourceFile = dctx.args.rootDocPath.map(p => dotty.tools.dotc.util.SourceFile(dotty.tools.io.AbstractFile.getFile(p), scala.io.Codec.UTF8)) + val sourceFile = dctx.args.rootDocPath.map(p => dotty.tools.dotc.util.SourceFile(dotty.tools.io.AbstractFile.getFile(p), new dotty.tools.io.PlainDirectory(dotty.tools.io.Directory(".")), scala.io.Codec.UTF8)) sourceFile.fold(dotty.tools.dotc.util.NoSourcePosition)(sf => dotty.tools.dotc.util.SourcePosition(sf, dotty.tools.dotc.util.Spans.NoSpan)) } else owner.pos.get.asInstanceOf[dotty.tools.dotc.util.SrcPos] diff --git a/tests/plugins/run/scriptWrapper/LineNumberPlugin_1.scala b/tests/plugins/run/scriptWrapper/LineNumberPlugin_1.scala index 5ec70e29cc76..5c92ec51cacb 100644 --- a/tests/plugins/run/scriptWrapper/LineNumberPlugin_1.scala +++ b/tests/plugins/run/scriptWrapper/LineNumberPlugin_1.scala @@ -41,7 +41,7 @@ class FixLineNumbers extends PluginPhase { report.error(s"could not find file $adjustedFile", tree.sourcePos) return tree case file => - SourceFile(file, scala.io.Codec.UTF8) + SourceFile(file, ctx.settings.sourceroot.value, scala.io.Codec.UTF8) val userCodeOffset = ctx.source.lineToOffset(codeMarkerLine + 1) // lines.take(codeMarkerLine).map(_.length).sum val lineMapper = LineMapper(codeMarkerLine, userCodeOffset, adjustedSrc)