diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 591169545..97306ae5e 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -21,6 +21,7 @@ import org.apache.logging.log4j.core.{ Appender => XAppender } import org.scalasbt.ipcsocket.Win32SecurityLevel import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition } import sbt.Keys._ +import sbt.OptionSyntax._ import sbt.Project.{ inConfig, inScope, @@ -91,6 +92,7 @@ import xsbti.{ FileConverter, Position } import scala.collection.immutable.ListMap import scala.concurrent.duration._ +import scala.util.Try import scala.util.control.NonFatal import scala.xml.NodeSeq @@ -415,7 +417,7 @@ object Defaults extends BuildCommon { sourcePositionMappers ++= { val fc = fileConverter.value if (reportAbsolutePath.value) { - List(toAbsoluteSourceMapper(fc)) + List(toAbsoluteSourceMapper(fc) _) } else Nil }, // The virtual file value cache needs to be global or sbt will run out of direct byte buffer memory. @@ -464,13 +466,21 @@ object Defaults extends BuildCommon { }, ) - private[sbt] def toAbsoluteSourceMapper(fc: FileConverter): Position => Option[Position] = { - pos => - val newPath: Optional[String] = pos.sourcePath - .map { id => - fc.toPath(VirtualFileRef.of(id)).toAbsolutePath.toString - } - Some( + private[sbt] def toAbsoluteSourceMapper(fc: FileConverter)(pos: Position): Option[Position] = { + def isValid(path: String): Boolean = { + Try(Paths.get(path)).map(_ => true).getOrElse(false) + } + + val newPath: Option[String] = pos + .sourcePath() + .asScala + .filter(isValid) + .map { path => + fc.toPath(VirtualFileRef.of(path)).toAbsolutePath.toString + } + + newPath + .map { path => new Position { override def line(): Optional[Integer] = pos.line() @@ -482,11 +492,12 @@ object Defaults extends BuildCommon { override def pointerSpace(): Optional[String] = pos.pointerSpace() - override def sourcePath(): Optional[String] = newPath + override def sourcePath(): Optional[String] = Optional.of(path) override def sourceFile(): Optional[File] = pos.sourceFile() } - ) + } + .orElse(Some(pos)) } // csrCacheDirectory is scoped to ThisBuild to allow customization.