diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index 44704e209a59..030875578aa0 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -475,7 +475,7 @@ object Interactive { Include.definitions | Include.overriding | Include.overridden) else sym.topLevelClass match { case cls: ClassSymbol => - val trees = Option(cls.sourceFile).map(InteractiveDriver.toUri) match { + val trees = Option(cls.sourceFile).flatMap(InteractiveDriver.toUriOption) match { case Some(uri) if driver.openedTrees.contains(uri) => driver.openedTrees(uri) case _ => // Symbol comes from the classpath diff --git a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala index 5ea200f3e03a..02fdc7acd9ec 100644 --- a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala +++ b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala @@ -265,7 +265,24 @@ class InteractiveDriver(val settings: List[String]) extends Driver { } object InteractiveDriver { - def toUri(file: AbstractFile): URI = Paths.get(file.path).toUri - def toUri(source: SourceFile): URI = toUri(source.file) + def toUriOption(file: AbstractFile): Option[URI] = + if (!file.exists) + None + else + try { + // We don't use file.file here since it'll be null + // for the VirtualFiles created by InteractiveDriver#toSource + // TODO: To avoid these round trip conversions, we could add an + // AbstractFile#toUri method and implement it by returning a constant + // passed as a parameter to a constructor of VirtualFile + Some(Paths.get(file.path).toUri) + } catch { + case e: InvalidPathException => + None + } + def toUriOption(source: SourceFile): Option[URI] = + if (!source.exists) + None + else + toUriOption(source.file) } - diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index c7a497403b7e..5972dcf5318d 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -315,7 +315,8 @@ class DottyLanguageServer extends LanguageServer Include.references | Include.definitions | Include.linkedClass | Include.overriding val refs = Interactive.findTreesMatching(trees, includes, sym) - val changes = refs.groupBy(ref => toUri(ref.source).toString) + val changes = refs.groupBy(ref => toUriOption(ref.source)) + .flatMap((uriOpt, ref) => uriOpt.map(uri => (uri.toString, ref))) .mapValues(refs => refs.flatMap(ref => range(ref.namePos, positionMapperFor(ref.source)).map(nameRange => new TextEdit(nameRange, newName))).asJava) @@ -433,7 +434,10 @@ object DottyLanguageServer { /** Convert a SourcePosition to an lsp4.Location */ def location(p: SourcePosition, positionMapper: Option[SourcePosition => SourcePosition] = None): Option[lsp4j.Location] = - range(p, positionMapper).map(r => new lsp4j.Location(toUri(p.source).toString, r)) + for { + uri <- toUriOption(p.source) + r <- range(p, positionMapper) + } yield new lsp4j.Location(uri.toString, r) /** * Convert a MessageContainer to an lsp4j.Diagnostic. The positions are transformed vy