From f3967a75c46c35f729ef2a9a6466de07bb4dd80a Mon Sep 17 00:00:00 2001 From: Katarzyna Marek Date: Tue, 19 Mar 2024 11:01:06 +0100 Subject: [PATCH] move logic outline files logic out of pc --- .../meta/internal/metals/Compilers.scala | 278 ++++++++++++------ .../metals/InteractiveSemanticdbs.scala | 16 +- .../metals/OutlineFilesProvider.scala | 191 ++++++++++++ .../java/scala/meta/pc/CompilerFiles.java | 6 - .../main/java/scala/meta/pc/OutlineFiles.java | 16 + .../scala/meta/pc/PresentationCompiler.java | 26 +- .../java/scala/meta/pc/VirtualFileParams.java | 9 + .../metals/CompilerOffsetParams.scala | 11 +- .../metals/CompilerVirtualFileParams.scala | 5 +- .../meta/internal/pc/CompilerWrapper.scala | 13 +- .../scala/meta/internal/pc/Compat.scala | 2 + .../scala/meta/internal/pc/Compat.scala | 12 +- .../scala/meta/internal/pc/Compat.scala | 10 +- .../scala/meta/internal/pc/MetalsGlobal.scala | 2 +- .../internal/pc/ScalaCompilerAccess.scala | 8 +- .../pc/ScalaPresentationCompiler.scala | 176 ++--------- .../internal/pc/Scala3CompilerWrapper.scala | 2 +- .../pc/ScalaPresentationCompiler.scala | 2 +- .../internal/metals/OffsetParamsUtils.scala | 30 +- .../test/scala/tests/CompilersLspSuite.scala | 4 +- 20 files changed, 512 insertions(+), 307 deletions(-) create mode 100644 metals/src/main/scala/scala/meta/internal/metals/OutlineFilesProvider.scala delete mode 100644 mtags-interfaces/src/main/java/scala/meta/pc/CompilerFiles.java create mode 100644 mtags-interfaces/src/main/java/scala/meta/pc/OutlineFiles.java diff --git a/metals/src/main/scala/scala/meta/internal/metals/Compilers.scala b/metals/src/main/scala/scala/meta/internal/metals/Compilers.scala index bf763a150cd..111d2b7d3f8 100644 --- a/metals/src/main/scala/scala/meta/internal/metals/Compilers.scala +++ b/metals/src/main/scala/scala/meta/internal/metals/Compilers.scala @@ -31,7 +31,6 @@ import scala.meta.internal.worksheets.WorksheetProvider import scala.meta.io.AbsolutePath import scala.meta.pc.AutoImportsResult import scala.meta.pc.CancelToken -import scala.meta.pc.CompilerFiles import scala.meta.pc.HoverSignature import scala.meta.pc.OffsetParams import scala.meta.pc.PresentationCompiler @@ -86,18 +85,7 @@ class Compilers( )(implicit ec: ExecutionContextExecutorService, rc: ReportContext) extends Cancelable { val plugins = new CompilerPlugins() - - class TargetCompilerFiles(targetId: BuildTargetIdentifier) - extends CompilerFiles { - override def allPaths(): ju.List[Path] = { - buildTargets - .buildTargetSources(targetId) - .flatMap(_.listRecursive.toList) - .map(_.toNIO) - .toList - .asJava - } - } + val outlineFilesProvider = new OutlineFilesProvider(buildTargets, buffers) // Not a TrieMap because we want to avoid loading duplicate compilers for the same build target. // Not a `j.u.c.ConcurrentHashMap` because it can deadlock in `computeIfAbsent` when the absent @@ -112,8 +100,6 @@ class Compilers( ) private val worksheetsDigests = new TrieMap[AbsolutePath, String]() - private val wasSuccessfullyCompiled = - new TrieMap[BuildTargetIdentifier, Boolean]() private val cache = jcache.asScala private def buildTargetPCFromCache( @@ -197,6 +183,7 @@ class Compilers( cache.clear() worksheetsCache.clear() worksheetsDigests.clear() + outlineFilesProvider.clear() } def restartAll(): Unit = { @@ -230,7 +217,7 @@ class Compilers( } def didClose(path: AbsolutePath): Unit = { - loadCompiler(path).foreach { pc => + loadCompiler(path).foreach { case (pc, _) => pc.didClose(path.toNIO.toUri()) } } @@ -241,7 +228,7 @@ class Compilers( .toInputFromBuffers(buffers) loadCompiler(path) - .map { pc => + .map { case (pc, id) => val inputAndAdjust = if ( path.isWorksheet && ScalaVersions.isScala3Version(pc.scalaVersion()) @@ -256,6 +243,8 @@ class Compilers( AdjustedLspData.default, ) + id.foreach(outlineFilesProvider.didChange(_, path)) + for { ds <- pc @@ -272,13 +261,19 @@ class Compilers( def didCompile(report: CompileReport): Unit = { val isSuccessful = report.getErrors == 0 - buildTargetPCFromCache(report.getTarget).foreach(_.restart(isSuccessful)) - - wasSuccessfullyCompiled.updateWith(report.getTarget()) { - case Some(true) => Some(true) - case _ => Some(isSuccessful) + buildTargetPCFromCache(report.getTarget).foreach { pc => + if ( + outlineFilesProvider.shouldRestartPc( + report.getTarget, + DidCompile(isSuccessful), + ) + ) { + pc.restart() + } } + outlineFilesProvider.onDidCompile(report.getTarget(), isSuccessful) + if (isSuccessful) { // Restart PC for all build targets that depend on this target since the classfiles // may have changed. @@ -286,7 +281,7 @@ class Compilers( for { target <- buildTargets.allInverseDependencies(report.getTarget) if target != report.getTarget - if wasSuccessfullyCompiled.getOrElse(target, true) + if outlineFilesProvider.shouldRestartPc(target, InverseDependency) compiler <- buildTargetPCFromCache(target) } { compiler.restart() @@ -355,7 +350,7 @@ class Compilers( } } loadCompiler(path) - .map { compiler => + .map { case (compiler, buildTargetId) => val input = path.toInputFromBuffers(buffers) breakpointPosition.toMeta(input) match { case Some(metaPos) => @@ -390,12 +385,14 @@ class Compilers( if (isZeroBased) i else i + 1 } - val offsetParams = CompilerOffsetParams( - path.toURI, - modified, - rangeEnd, - token, - ) + val offsetParams = + CompilerOffsetParams( + path.toURI, + modified, + rangeEnd, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) val previousLines = expression .getText() @@ -449,7 +446,7 @@ class Compilers( } else { val path = params.getTextDocument.getUri.toAbsolutePath loadCompiler(path) - .map { compiler => + .map { case (compiler, buildTargetId) => val (input, _, adjust) = sourceAdjustments( params.getTextDocument().getUri(), @@ -550,7 +547,12 @@ class Compilers( } val vFile = - CompilerVirtualFileParams(path.toNIO.toUri(), input.text, token) + CompilerVirtualFileParams( + path.toNIO.toUri(), + input.text, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) val isScala3 = ScalaVersions.isScala3Version(compiler.scalaVersion()) compiler @@ -592,7 +594,7 @@ class Compilers( token: CancelToken, ): Future[ju.List[DecorationOptions]] = { loadCompiler(path) - .map { compiler => + .map { case (compiler, buildTargetId) => val (input, _, adjust) = sourceAdjustments( path.toNIO.toUri().toString(), @@ -615,7 +617,12 @@ class Compilers( }.asJava } val vFile = - CompilerVirtualFileParams(path.toNIO.toUri(), input.text, token) + CompilerVirtualFileParams( + path.toNIO.toUri(), + input.text, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) val pcParams = CompilerSyntheticDecorationsParams( vFile, @@ -641,9 +648,10 @@ class Compilers( params: CompletionParams, token: CancelToken, ): Future[CompletionList] = - withPCAndAdjustLsp(params) { (pc, pos, adjust) => + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + val outlineFiles = outlineFilesProvider.getOutlineFiles(buildTargetId) val offsetParams = - CompilerOffsetParamsUtils.fromPos(pos, token) + CompilerOffsetParamsUtils.fromPos(pos, token, outlineFiles) pc.complete(offsetParams) .asScala .map { list => @@ -658,10 +666,14 @@ class Compilers( findExtensionMethods: Boolean, token: CancelToken, ): Future[ju.List[AutoImportsResult]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => pc.autoImports( name, - CompilerOffsetParamsUtils.fromPos(pos, token), + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ), findExtensionMethods, ).asScala .map { list => @@ -675,9 +687,14 @@ class Compilers( params: TextDocumentPositionParams, token: CancelToken, ): Future[ju.List[TextEdit]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => - pc.insertInferredType(CompilerOffsetParamsUtils.fromPos(pos, token)) - .asScala + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + pc.insertInferredType( + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ).asScala .map { edits => adjust.adjustTextEdits(edits) } @@ -688,9 +705,14 @@ class Compilers( params: TextDocumentPositionParams, token: CancelToken, ): Future[ju.List[TextEdit]] = - withPCAndAdjustLsp(params) { (pc, pos, adjust) => - pc.inlineValue(CompilerOffsetParamsUtils.fromPos(pos, token)) - .asScala + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + pc.inlineValue( + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ).asScala .map(adjust.adjustTextEdits) }.getOrElse(Future.successful(Nil.asJava)) @@ -698,9 +720,14 @@ class Compilers( params: TextDocumentPositionParams, token: CancelToken, ): Future[ju.List[DocumentHighlight]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => - pc.documentHighlight(CompilerOffsetParamsUtils.fromPos(pos, token)) - .asScala + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + pc.documentHighlight( + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ).asScala .map { highlights => adjust.adjustDocumentHighlight(highlights) } @@ -714,9 +741,13 @@ class Compilers( token: CancelToken, ): Future[ju.List[TextEdit]] = { withPCAndAdjustLsp(doc.getUri(), range, extractionPos) { - (pc, metaRange, metaExtractionPos, adjust) => + (pc, metaRange, metaExtractionPos, adjust, buildTargetId) => pc.extractMethod( - CompilerRangeParamsUtils.fromPos(metaRange, token), + CompilerRangeParamsUtils.fromPos( + metaRange, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ), CompilerOffsetParamsUtils.fromPos(metaExtractionPos, token), ).asScala .map { edits => @@ -730,9 +761,13 @@ class Compilers( argIndices: ju.List[Integer], token: CancelToken, ): Future[ju.List[TextEdit]] = { - withPCAndAdjustLsp(position) { (pc, pos, adjust) => + withPCAndAdjustLsp(position) { (pc, pos, adjust, buildTargetId) => pc.convertToNamedArguments( - CompilerOffsetParamsUtils.fromPos(pos, token), + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ), argIndices, ).asScala .map { edits => @@ -745,9 +780,14 @@ class Compilers( params: TextDocumentPositionParams, token: CancelToken, ): Future[ju.List[TextEdit]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => - pc.implementAbstractMembers(CompilerOffsetParamsUtils.fromPos(pos, token)) - .asScala + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + pc.implementAbstractMembers( + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ).asScala .map { edits => adjust.adjustTextEdits(edits) } @@ -758,9 +798,14 @@ class Compilers( params: HoverExtParams, token: CancelToken, ): Future[Option[HoverSignature]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => - pc.hover(CompilerRangeParamsUtils.offsetOrRange(pos, token)) - .asScala + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + pc.hover( + CompilerRangeParamsUtils.offsetOrRange( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ).asScala .map(_.asScala.map { hover => adjust.adjustHoverResp(hover) }) } }.getOrElse(Future.successful(None)) @@ -769,9 +814,13 @@ class Compilers( params: TextDocumentPositionParams, token: CancelToken, ): Future[ju.Optional[LspRange]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => pc.prepareRename( - CompilerRangeParamsUtils.offsetOrRange(pos, token) + CompilerRangeParamsUtils.offsetOrRange( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) ).asScala .map { range => range.map(adjust.adjustRange(_)) @@ -783,9 +832,13 @@ class Compilers( params: RenameParams, token: CancelToken, ): Future[ju.List[TextEdit]] = { - withPCAndAdjustLsp(params) { (pc, pos, adjust) => + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => pc.rename( - CompilerRangeParamsUtils.offsetOrRange(pos, token), + CompilerRangeParamsUtils.offsetOrRange( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ), params.getNewName(), ).asScala .map { edits => @@ -813,8 +866,12 @@ class Compilers( token: CancelToken, findTypeDef: Boolean, ): Future[DefinitionResult] = - withPCAndAdjustLsp(params) { (pc, pos, adjust) => - val params = CompilerOffsetParamsUtils.fromPos(pos, token) + withPCAndAdjustLsp(params) { (pc, pos, adjust, buildTargetId) => + val params = CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) val defResult = if (findTypeDef) pc.typeDefinition(params) else @@ -848,41 +905,55 @@ class Compilers( params: TextDocumentPositionParams, token: CancelToken, ): Future[SignatureHelp] = - withPCAndAdjustLsp(params) { (pc, pos, _) => - pc.signatureHelp(CompilerOffsetParamsUtils.fromPos(pos, token)).asScala + withPCAndAdjustLsp(params) { (pc, pos, _, buildTargetId) => + pc.signatureHelp( + CompilerOffsetParamsUtils.fromPos( + pos, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ).asScala }.getOrElse(Future.successful(new SignatureHelp())) def selectionRange( params: SelectionRangeParams, token: CancelToken, ): Future[ju.List[SelectionRange]] = { - withPCAndAdjustLsp(params) { (pc, positions) => + withPCAndAdjustLsp(params) { (pc, positions, buildTargetId) => val offsetPositions: ju.List[OffsetParams] = - positions.map(CompilerOffsetParamsUtils.fromPos(_, token)) + positions.map( + CompilerOffsetParamsUtils.fromPos( + _, + token, + outlineFilesProvider.getOutlineFiles(buildTargetId), + ) + ) pc.selectionRange(offsetPositions).asScala }.getOrElse(Future.successful(Nil.asJava)) } def loadCompiler( path: AbsolutePath - ): Option[PresentationCompiler] = { + ): Option[(PresentationCompiler, Option[BuildTargetIdentifier])] = { - def fromBuildTarget: Option[PresentationCompiler] = { + def fromBuildTarget + : Option[(PresentationCompiler, Option[BuildTargetIdentifier])] = { val target = buildTargets .inverseSources(path) target match { - case None => Some(fallbackCompiler(path)) + case None => Some((fallbackCompiler(path), None)) case Some(value) => - if (path.isScalaFilename) loadCompiler(value) - else if (path.isJavaFilename) loadJavaCompiler(value) + if (path.isScalaFilename) loadCompiler(value).map((_, Some(value))) + else if (path.isJavaFilename) + loadJavaCompiler(value).map((_, Some(value))) else None } } if (!path.isScalaFilename && !path.isJavaFilename) None else if (path.isWorksheet) - loadWorksheetCompiler(path).orElse(fromBuildTarget) + loadWorksheetCompiler(path).map((_, None)).orElse(fromBuildTarget) else fromBuildTarget } @@ -1039,9 +1110,15 @@ class Compilers( private def withPCAndAdjustLsp[T]( params: SelectionRangeParams - )(fn: (PresentationCompiler, ju.List[Position]) => T): Option[T] = { + )( + fn: ( + PresentationCompiler, + ju.List[Position], + Option[BuildTargetIdentifier], + ) => T + ): Option[T] = { val path = params.getTextDocument.getUri.toAbsolutePath - loadCompiler(path).map { compiler => + loadCompiler(path).map { case (compiler, buildTargetId) => val input = path .toInputFromBuffers(buffers) .copy(path = params.getTextDocument.getUri) @@ -1049,21 +1126,30 @@ class Compilers( val positions = params.getPositions().asScala.flatMap(_.toMeta(input)).asJava - fn(compiler, positions) + fn(compiler, positions, buildTargetId) } } private def withPCAndAdjustLsp[T]( params: TextDocumentPositionParams - )(fn: (PresentationCompiler, Position, AdjustLspData) => T): Option[T] = { + )( + fn: ( + PresentationCompiler, + Position, + AdjustLspData, + Option[BuildTargetIdentifier], + ) => T + ): Option[T] = { val path = params.getTextDocument.getUri.toAbsolutePath - loadCompiler(path).flatMap { compiler => + loadCompiler(path).flatMap { case (compiler, buildTargetId) => val (input, pos, adjust) = sourceAdjustments( params, compiler.scalaVersion(), ) - pos.toMeta(input).map(metaPos => fn(compiler, metaPos, adjust)) + pos + .toMeta(input) + .map(metaPos => fn(compiler, metaPos, adjust, buildTargetId)) } } @@ -1077,10 +1163,11 @@ class Compilers( Position, Position, AdjustLspData, + Option[BuildTargetIdentifier], ) => T ): Option[T] = { val path = uri.toAbsolutePath - loadCompiler(path).flatMap { compiler => + loadCompiler(path).flatMap { case (compiler, buildTargetId) => val (input, adjustRequest, adjustResponse) = sourceAdjustments( uri, @@ -1092,22 +1179,35 @@ class Compilers( adjustRequest(range.getEnd()), ).toMeta(input) metaExtractionPos <- adjustRequest(extractionPos).toMeta(input) - } yield fn(compiler, metaRange, metaExtractionPos, adjustResponse) + } yield fn( + compiler, + metaRange, + metaExtractionPos, + adjustResponse, + buildTargetId, + ) } } private def withPCAndAdjustLsp[T]( params: HoverExtParams - )(fn: (PresentationCompiler, Position, AdjustLspData) => T): Option[T] = { + )( + fn: ( + PresentationCompiler, + Position, + AdjustLspData, + Option[BuildTargetIdentifier], + ) => T + ): Option[T] = { val path = params.textDocument.getUri.toAbsolutePath - loadCompiler(path).flatMap { compiler => + loadCompiler(path).flatMap { case (compiler, buildTargetId) => if (params.range != null) { val (input, range, adjust) = sourceAdjustments( params, compiler.scalaVersion(), ) - range.toMeta(input).map(fn(compiler, _, adjust)) + range.toMeta(input).map(fn(compiler, _, adjust, buildTargetId)) } else { val positionParams = @@ -1119,7 +1219,7 @@ class Compilers( positionParams, compiler.scalaVersion(), ) - pos.toMeta(input).map(fn(compiler, _, adjust)) + pos.toMeta(input).map(fn(compiler, _, adjust, buildTargetId)) } } } @@ -1196,19 +1296,13 @@ class Compilers( classpath: Seq[Path], search: SymbolSearch, ): PresentationCompiler = { - val pc = newCompiler( + newCompiler( mtags, target.scalac.getOptions().asScala.toSeq, classpath, search, target.scalac.getTarget.getUri, ).withBuildTargetName(target.displayName) - .withCompilerFiles(new TargetCompilerFiles(target.id)) - - wasSuccessfullyCompiled - .get(target.scalac.getTarget()) - .map(pc.withWasSuccessfullyCompiled) - .getOrElse(pc) } def newCompiler( diff --git a/metals/src/main/scala/scala/meta/internal/metals/InteractiveSemanticdbs.scala b/metals/src/main/scala/scala/meta/internal/metals/InteractiveSemanticdbs.scala index e49bc9754e0..14e36679b17 100644 --- a/metals/src/main/scala/scala/meta/internal/metals/InteractiveSemanticdbs.scala +++ b/metals/src/main/scala/scala/meta/internal/metals/InteractiveSemanticdbs.scala @@ -152,17 +152,19 @@ final class InteractiveSemanticdbs( def fromTarget = for { buildTarget <- buildTargets.inverseSources(source) pc <- compilers().loadCompiler(buildTarget) - } yield pc + } yield (pc, Some(buildTarget)) - val pc = worksheetCompiler + val (pc, optBuildTarget) = worksheetCompiler + .map((_, None)) .orElse(fromTarget) .orElse { // load presentation compiler for sources that were create by a worksheet definition request tables.worksheetSources .getWorksheet(source) .flatMap(compilers().loadWorksheetCompiler) + .map((_, None)) } - .getOrElse(compilers().fallbackCompiler(source)) + .getOrElse((compilers().fallbackCompiler(source), None)) val (prependedLinesSize, modifiedText) = buildTargets @@ -174,8 +176,14 @@ final class InteractiveSemanticdbs( // NOTE(olafur): it's unfortunate that we block on `semanticdbTextDocument` // here but to avoid it we would need to refactor the `Semanticdbs` trait, // which requires more effort than it's worth. + val params = new CompilerVirtualFileParams( + source.toURI, + modifiedText, + outlineFiles = + compilers().outlineFilesProvider.getOutlineFiles(optBuildTarget), + ) val bytes = pc - .semanticdbTextDocument(source.toURI, modifiedText) + .semanticdbTextDocument(params) .get( clientConfig.initialConfig.compilers.timeoutDelay, clientConfig.initialConfig.compilers.timeoutUnit, diff --git a/metals/src/main/scala/scala/meta/internal/metals/OutlineFilesProvider.scala b/metals/src/main/scala/scala/meta/internal/metals/OutlineFilesProvider.scala new file mode 100644 index 00000000000..3ddc52e2cb2 --- /dev/null +++ b/metals/src/main/scala/scala/meta/internal/metals/OutlineFilesProvider.scala @@ -0,0 +1,191 @@ +package scala.meta.internal.metals + +import java.util.Optional +import java.util.concurrent.atomic.AtomicBoolean +import java.{util => ju} + +import scala.collection.concurrent.TrieMap + +import scala.meta.internal.metals.MetalsEnrichments._ +import scala.meta.io.AbsolutePath +import scala.meta.pc.VirtualFileParams +import scala.meta.pc.{OutlineFiles => JOutlineFiles} + +import ch.epfl.scala.bsp4j.BuildTargetIdentifier + +class OutlineFilesProvider( + buildTargets: BuildTargets, + buffers: Buffers, +) { + private val outlineFiles = + new TrieMap[BuildTargetIdentifier, BuildTargetOutlineFilesProvider]() + + def shouldRestartPc( + id: BuildTargetIdentifier, + reason: PcRestartReason, + ): Boolean = { + reason match { + case DidCompile(true) => true + case _ => + outlineFiles.get(id) match { + case Some(provider) => + // if it was never compiled successfully by the build server + // we don't restart pc not to lose information from outline compile + provider.wasSuccessfullyCompiledByBuildServer + case None => true + } + } + } + + def onDidCompile(id: BuildTargetIdentifier, wasSuccessful: Boolean): Unit = { + outlineFiles.get(id) match { + case Some(provider) => + if (wasSuccessful) provider.successfulCompilation() + case None => + for { + scalaTarget <- buildTargets.scalaTarget(id) + // we don't perform outline compilation for Scala 3 + if (!ScalaVersions.isScala3Version(scalaTarget.scalaVersion)) + } outlineFiles.putIfAbsent( + id, + new BuildTargetOutlineFilesProvider( + buildTargets, + buffers, + id, + wasSuccessful, + ), + ) + } + } + + def didChange(id: BuildTargetIdentifier, path: AbsolutePath): Unit = { + for { + provider <- outlineFiles.get(id) + } provider.didChange(path) + } + + def getOutlineFiles( + buildTargetId: Option[BuildTargetIdentifier] + ): Optional[JOutlineFiles] = { + val res: Option[JOutlineFiles] = + for { + id <- buildTargetId + provider <- outlineFiles.get(id) + outlineFiles <- provider.outlineFiles() + } yield outlineFiles + res.asJava + } + + def enrichWithOutlineFiles( + buildTargetId: Option[BuildTargetIdentifier] + )(vFile: CompilerVirtualFileParams): CompilerVirtualFileParams = { + val optOutlineFiles = + for { + id <- buildTargetId + provider <- outlineFiles.get(id) + outlineFiles <- provider.outlineFiles() + } yield outlineFiles + + optOutlineFiles + .map(outlineFiles => vFile.copy(outlineFiles = Optional.of(outlineFiles))) + .getOrElse(vFile) + } + + def enrichWithOutlineFiles( + path: AbsolutePath + )(vFile: CompilerVirtualFileParams): CompilerVirtualFileParams = { + val optOutlineFiles = + for { + bt <- buildTargets.inferBuildTarget(path) + provider <- outlineFiles.get(bt) + outlineFiles <- provider.outlineFiles() + } yield outlineFiles + + optOutlineFiles + .map(outlineFiles => vFile.copy(outlineFiles = Optional.of(outlineFiles))) + .getOrElse(vFile) + } + + def clear(): Unit = { + outlineFiles.clear() + } +} + +class BuildTargetOutlineFilesProvider( + buildTargets: BuildTargets, + buffers: Buffers, + id: BuildTargetIdentifier, + wasCompilationSuccessful: Boolean, +) { + private val changedDocuments = + ConcurrentHashSet.empty[AbsolutePath] + + private val wasAllOutlined: AtomicBoolean = + new AtomicBoolean(false) + + private val wasSuccessfullyCompiled: AtomicBoolean = + new AtomicBoolean(wasCompilationSuccessful) + + def wasSuccessfullyCompiledByBuildServer: Boolean = + wasSuccessfullyCompiled.get() + + def successfulCompilation(): Unit = { + wasSuccessfullyCompiled.set(true) + changedDocuments.clear() + } + + def didChange(path: AbsolutePath): Boolean = + changedDocuments.add(path) + + def outlineFiles(): Option[OutlineFiles] = { + if (!wasSuccessfullyCompiled.get() && !wasAllOutlined.getAndSet(true)) { + // initial outline compilation that is a substitute for build server compilation + val allFiles = + buildTargets + .buildTargetSources(id) + .flatMap(_.listRecursive.toList) + .flatMap(toVirtualFileParams(_)) + .toList + .asJava + Some( + OutlineFiles( + allFiles, + isFirstCompileSubstitute = true, + ) + ) + } else { + changedDocuments.asScala.toList.flatMap( + toVirtualFileParams + ) match { + case Nil => None + case files => + Some( + OutlineFiles( + files.asJava, + isFirstCompileSubstitute = false, + ) + ) + } + } + } + + private def toVirtualFileParams( + path: AbsolutePath + ): Option[VirtualFileParams] = + buffers.get(path).orElse(path.readTextOpt).map { text => + new CompilerVirtualFileParams( + path.toURI, + text, + ) + } + +} + +sealed trait PcRestartReason +case object InverseDependency extends PcRestartReason +case class DidCompile(wasSuccess: Boolean) extends PcRestartReason + +case class OutlineFiles( + files: ju.List[VirtualFileParams], + isFirstCompileSubstitute: Boolean = false, +) extends JOutlineFiles diff --git a/mtags-interfaces/src/main/java/scala/meta/pc/CompilerFiles.java b/mtags-interfaces/src/main/java/scala/meta/pc/CompilerFiles.java deleted file mode 100644 index 68adb2acfed..00000000000 --- a/mtags-interfaces/src/main/java/scala/meta/pc/CompilerFiles.java +++ /dev/null @@ -1,6 +0,0 @@ -package scala.meta.pc; - -public interface CompilerFiles { - - java.util.List allPaths(); -} diff --git a/mtags-interfaces/src/main/java/scala/meta/pc/OutlineFiles.java b/mtags-interfaces/src/main/java/scala/meta/pc/OutlineFiles.java new file mode 100644 index 00000000000..28cd919872b --- /dev/null +++ b/mtags-interfaces/src/main/java/scala/meta/pc/OutlineFiles.java @@ -0,0 +1,16 @@ +package scala.meta.pc; +import java.util.List; + +public interface OutlineFiles { + + /** + * Will this outline compilation be substitute for build server's compilation. + * Used if the first compilation using build server is unsuccessful. + */ + boolean isFirstCompileSubstitute(); + + /** + * Files that should be outline compiled before calculating result. + */ + List files(); +} diff --git a/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java b/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java index ad3cdf3209d..acaf2e33224 100644 --- a/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java +++ b/mtags-interfaces/src/main/java/scala/meta/pc/PresentationCompiler.java @@ -182,6 +182,14 @@ public CompletableFuture> syntheticDecorations(Synthet */ public abstract CompletableFuture semanticdbTextDocument(URI filename, String code); + /** + * Returns the Protobuf byte array representation of a SemanticDB + * TextDocument for the given source. + */ + public CompletableFuture semanticdbTextDocument(VirtualFileParams params) { + return semanticdbTextDocument(params.uri(), params.text()); + } + /** * Return the selections ranges for the given positions. */ @@ -203,13 +211,6 @@ public CompletableFuture> syntheticDecorations(Synthet */ public abstract void shutdown(); - /** - * Clean the symbol table and other mutable state in the compiler. - */ - public void restart(boolean successfulCompilation) { - restart(); - } - /** * Clean the symbol table and other mutable state in the compiler. */ @@ -229,13 +230,6 @@ public PresentationCompiler withBuildTargetName(String buildTargetName) { return this; }; - /** - * Set an ability to search for all files within the compiler - */ - public PresentationCompiler withCompilerFiles(CompilerFiles files) { - return this; - }; - /** * Provide a SymbolSearch to extract docstrings, java parameter names and Scala * default parameter values. @@ -324,8 +318,4 @@ public abstract PresentationCompiler newInstance(String buildTargetIdentifier, L */ public abstract String scalaVersion(); - public PresentationCompiler withWasSuccessfullyCompiled(boolean wasSuccessful) { - return this; - } - } diff --git a/mtags-interfaces/src/main/java/scala/meta/pc/VirtualFileParams.java b/mtags-interfaces/src/main/java/scala/meta/pc/VirtualFileParams.java index 904cb7da0fd..5a534e82203 100644 --- a/mtags-interfaces/src/main/java/scala/meta/pc/VirtualFileParams.java +++ b/mtags-interfaces/src/main/java/scala/meta/pc/VirtualFileParams.java @@ -1,6 +1,7 @@ package scala.meta.pc; import java.net.URI; +import java.util.Optional; /** * Parameters for a presentation compiler request at a given offset in a single source file. @@ -21,6 +22,14 @@ public interface VirtualFileParams { */ CancelToken token(); + /** + * Information about files that changed since last compilation + * and should be outline compiled. + */ + default Optional outlineFiles() { + return Optional.empty(); + } + default void checkCanceled() { token().checkCanceled(); } diff --git a/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerOffsetParams.scala b/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerOffsetParams.scala index 71b3223d226..ecfc5fe03de 100644 --- a/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerOffsetParams.scala +++ b/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerOffsetParams.scala @@ -1,16 +1,19 @@ package scala.meta.internal.metals import java.net.URI +import java.util.Optional import scala.meta.pc.CancelToken import scala.meta.pc.OffsetParams +import scala.meta.pc.OutlineFiles import scala.meta.pc.RangeParams case class CompilerOffsetParams( uri: URI, text: String, offset: Int, - token: CancelToken = EmptyCancelToken + token: CancelToken = EmptyCancelToken, + override val outlineFiles: Optional[OutlineFiles] = Optional.empty() ) extends OffsetParams case class CompilerRangeParams( @@ -18,13 +21,15 @@ case class CompilerRangeParams( text: String, offset: Int, endOffset: Int, - token: CancelToken = EmptyCancelToken + token: CancelToken = EmptyCancelToken, + override val outlineFiles: Optional[OutlineFiles] = Optional.empty() ) extends RangeParams { def toCompilerOffsetParams: CompilerOffsetParams = CompilerOffsetParams( uri, text, offset, - token + token, + outlineFiles ) } diff --git a/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerVirtualFileParams.scala b/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerVirtualFileParams.scala index 954d3b0514a..0f57beba651 100644 --- a/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerVirtualFileParams.scala +++ b/mtags-shared/src/main/scala/scala/meta/internal/metals/CompilerVirtualFileParams.scala @@ -1,12 +1,15 @@ package scala.meta.internal.metals import java.net.URI +import java.util.Optional import scala.meta.pc.CancelToken +import scala.meta.pc.OutlineFiles import scala.meta.pc.VirtualFileParams case class CompilerVirtualFileParams( uri: URI, text: String, - token: CancelToken = EmptyCancelToken + token: CancelToken = EmptyCancelToken, + override val outlineFiles: Optional[OutlineFiles] = Optional.empty() ) extends VirtualFileParams diff --git a/mtags-shared/src/main/scala/scala/meta/internal/pc/CompilerWrapper.scala b/mtags-shared/src/main/scala/scala/meta/internal/pc/CompilerWrapper.scala index 8836721b802..04246adf40e 100644 --- a/mtags-shared/src/main/scala/scala/meta/internal/pc/CompilerWrapper.scala +++ b/mtags-shared/src/main/scala/scala/meta/internal/pc/CompilerWrapper.scala @@ -14,19 +14,10 @@ trait CompilerWrapper[Reporter, Compiler] { def stop(): Unit - def compiler(changeFiles: OutlineFiles): Compiler + def compiler(params: VirtualFileParams): Compiler = compiler() - def compiler(): Compiler = compiler(OutlineFiles.empty) + def compiler(): Compiler def presentationCompilerThread: Option[Thread] } - -case class OutlineFiles( - files: List[VirtualFileParams], - firstCompileSubstitute: Boolean = false -) - -object OutlineFiles { - def empty: OutlineFiles = OutlineFiles(Nil) -} diff --git a/mtags/src/main/scala-2.11/scala/meta/internal/pc/Compat.scala b/mtags/src/main/scala-2.11/scala/meta/internal/pc/Compat.scala index 8b77efec49d..e4e177109fc 100644 --- a/mtags/src/main/scala-2.11/scala/meta/internal/pc/Compat.scala +++ b/mtags/src/main/scala-2.11/scala/meta/internal/pc/Compat.scala @@ -3,6 +3,8 @@ package scala.meta.internal.pc import scala.tools.nsc.reporters.Reporter import scala.tools.nsc.reporters.StoreReporter +import scala.meta.pc.OutlineFiles + trait Compat { this: MetalsGlobal => def metalsFunctionArgTypes(tpe: Type): List[Type] = { val dealiased = tpe.dealiasWiden diff --git a/mtags/src/main/scala-2.12/scala/meta/internal/pc/Compat.scala b/mtags/src/main/scala-2.12/scala/meta/internal/pc/Compat.scala index cc1c8c51a6f..8532ab9e00d 100644 --- a/mtags/src/main/scala-2.12/scala/meta/internal/pc/Compat.scala +++ b/mtags/src/main/scala-2.12/scala/meta/internal/pc/Compat.scala @@ -1,8 +1,12 @@ package scala.meta.internal.pc -import scala.tools.nsc.reporters.Reporter +import java.{util => ju} + +import scala.reflect.internal.Reporter import scala.tools.nsc.reporters.StoreReporter +import scala.meta.internal.jdk.CollectionConverters._ +import scala.meta.pc.OutlineFiles import scala.meta.pc.VirtualFileParams trait Compat { this: MetalsGlobal => @@ -22,7 +26,7 @@ trait Compat { this: MetalsGlobal => def runOutline(files: OutlineFiles): Unit = { this.settings.Youtline.value = true runOutline(files.files) - if (files.firstCompileSubstitute) { + if (files.isFirstCompileSubstitute()) { // if first compilation substitute we compile all files twice // first to emit symbols, second so signatures have information about those symbols // this isn't a perfect strategy but much better than single compile @@ -32,10 +36,10 @@ trait Compat { this: MetalsGlobal => } private def runOutline( - files: List[VirtualFileParams], + files: ju.List[VirtualFileParams], forceNewUnit: Boolean = false ): Unit = { - files.foreach { params => + files.asScala.foreach { params => val unit = this.addCompilationUnit( params.text(), params.uri.toString(), diff --git a/mtags/src/main/scala-2.13/scala/meta/internal/pc/Compat.scala b/mtags/src/main/scala-2.13/scala/meta/internal/pc/Compat.scala index 19e8ec15b9c..0b4fe757b10 100644 --- a/mtags/src/main/scala-2.13/scala/meta/internal/pc/Compat.scala +++ b/mtags/src/main/scala-2.13/scala/meta/internal/pc/Compat.scala @@ -1,8 +1,12 @@ package scala.meta.internal.pc +import java.{util => ju} + import scala.reflect.internal.Reporter import scala.tools.nsc.reporters.StoreReporter +import scala.meta.internal.jdk.CollectionConverters._ +import scala.meta.pc.OutlineFiles import scala.meta.pc.VirtualFileParams trait Compat { this: MetalsGlobal => @@ -29,7 +33,7 @@ trait Compat { this: MetalsGlobal => def runOutline(files: OutlineFiles): Unit = { this.settings.Youtline.value = true runOutline(files.files) - if (files.firstCompileSubstitute) { + if (files.isFirstCompileSubstitute()) { // if first compilation substitute we compile all files twice // first to emit symbols, second so signatures have information about those symbols // this isn't a perfect strategy but much better than single compile @@ -39,10 +43,10 @@ trait Compat { this: MetalsGlobal => } private def runOutline( - files: List[VirtualFileParams], + files: ju.List[VirtualFileParams], forceNewUnit: Boolean = false ): Unit = { - files.foreach { params => + files.asScala.foreach { params => val unit = this.addCompilationUnit( params.text(), params.uri.toString(), diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala index 4bc0c4cfef5..107dbf01f14 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/MetalsGlobal.scala @@ -69,7 +69,7 @@ class MetalsGlobal( val richCompilationCache: TrieMap[String, RichCompilationUnit] = TrieMap.empty[String, RichCompilationUnit] - // for those paths units were + // for those paths units were fully compiled (not just outlined) val fullyCompiled: mutable.Set[String] = mutable.Set.empty[String] class MetalsInteractiveAnalyzer(val global: compiler.type) diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaCompilerAccess.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaCompilerAccess.scala index 3ad5ab0d4b7..4184176b534 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaCompilerAccess.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaCompilerAccess.scala @@ -9,14 +9,18 @@ import scala.util.control.NonFatal import scala.meta.internal.metals.ReportContext import scala.meta.pc.PresentationCompilerConfig +import scala.meta.pc.VirtualFileParams class ScalaCompilerWrapper(global: MetalsGlobal) extends CompilerWrapper[StoreReporter, MetalsGlobal] { - override def compiler(files: OutlineFiles): MetalsGlobal = { - global.runOutline(files) + override def compiler(params: VirtualFileParams): MetalsGlobal = { + if (params.outlineFiles().isPresent()) { + global.runOutline(params.outlineFiles().get()) + } global } + override def compiler(): MetalsGlobal = global override def resetReporter(): Unit = global.reporter.reset() diff --git a/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaPresentationCompiler.scala b/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaPresentationCompiler.scala index 9df612561b0..695db9ad213 100644 --- a/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaPresentationCompiler.scala +++ b/mtags/src/main/scala-2/scala/meta/internal/pc/ScalaPresentationCompiler.scala @@ -2,7 +2,6 @@ package scala.meta.internal.pc import java.io.File import java.net.URI -import java.nio.file.Files import java.nio.file.Path import java.util import java.util.Optional @@ -13,27 +12,22 @@ import java.util.logging.Logger import java.{util => ju} import scala.collection.Seq -import scala.collection.concurrent.TrieMap import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContextExecutor import scala.reflect.io.VirtualDirectory import scala.tools.nsc.Settings import scala.tools.nsc.reporters.StoreReporter -import scala.util.control.NonFatal import scala.meta.internal.jdk.CollectionConverters._ -import scala.meta.internal.metals.CompilerOffsetParams import scala.meta.internal.metals.CompilerVirtualFileParams import scala.meta.internal.metals.EmptyCancelToken import scala.meta.internal.metals.EmptyReportContext -import scala.meta.internal.metals.Report import scala.meta.internal.metals.ReportContext import scala.meta.internal.metals.ReportLevel import scala.meta.internal.metals.StdReportContext import scala.meta.internal.mtags.BuildInfo import scala.meta.internal.mtags.MtagsEnrichments._ import scala.meta.pc.AutoImportsResult -import scala.meta.pc.CompilerFiles import scala.meta.pc.DefinitionResult import scala.meta.pc.DisplayableException import scala.meta.pc.HoverSignature @@ -66,25 +60,13 @@ case class ScalaPresentationCompiler( sh: Option[ScheduledExecutorService] = None, config: PresentationCompilerConfig = PresentationCompilerConfigImpl(), folderPath: Option[Path] = None, - reportsLevel: ReportLevel = ReportLevel.Info, - compilerFiles: Option[CompilerFiles] = None, - wasSuccessfullyCompiledInitial: Option[Boolean] = None + reportsLevel: ReportLevel = ReportLevel.Info ) extends PresentationCompiler { - private val wasSuccessfullyCompiled = - new util.concurrent.atomic.AtomicReference[ - CompilationStatus.WasSuccessfullyCompiled - ]( - CompilationStatus.fromWasSuccessfullyCompiled( - wasSuccessfullyCompiledInitial - ) - ) - implicit val executionContext: ExecutionContextExecutor = ec val scalaVersion = BuildInfo.scalaCompilerVersion - private val changedDocuments = TrieMap.empty[URI, VirtualFileParams] val logger: Logger = Logger.getLogger(classOf[ScalaPresentationCompiler].getName) @@ -117,11 +99,6 @@ case class ScalaPresentationCompiler( ): PresentationCompiler = copy(sh = Some(sh)) - override def withCompilerFiles( - compilerFiles: CompilerFiles - ): PresentationCompiler = - copy(compilerFiles = Some(compilerFiles)) - override def withConfiguration( config: PresentationCompilerConfig ): PresentationCompiler = @@ -153,57 +130,7 @@ case class ScalaPresentationCompiler( compilerAccess.shutdown() } - def restart(): Unit = restoreOutlineAndRestart() - - override def restart(wasSuccessful: Boolean): Unit = { - val prevCompilationStatus = wasSuccessfullyCompiled.getAndUpdate { - case _ if wasSuccessful => - CompilationStatus.SuccessfullyCompiled - case CompilationStatus.WaitingForCompilationResult => - CompilationStatus.UnSuccessfullyCompiled - case value => value - } - - if (wasSuccessful) { - changedDocuments.clear() - compilerAccess.shutdownCurrentCompiler() - } else if ( - prevCompilationStatus == CompilationStatus.WaitingForCompilationResult - ) { - restoreOutlineAndRestart() - } - } - - private def restoreOutlineAndRestart() = { - compilerAccess - .withNonInterruptableCompiler(None)( - (), - EmptyCancelToken - ) { pc => - /* we will still want outline recompiled if the compilation was not succesful */ - pc.compiler().richCompilationCache.foreach { case (uriString, unit) => - try { - val text = unit.source.content.mkString - val uri = uriString.toAbsolutePath.toURI - val params = - CompilerOffsetParams(uri, text, 0, EmptyCancelToken) - changedDocuments += uri -> params - } catch { - case NonFatal(error) => - reportContex.incognito.create( - Report( - "restoring_cache", - "Error while restoring outline compiler cache", - error - ) - ) - logger - .log(util.logging.Level.SEVERE, error.getMessage(), error) - } - } - } - .get() - + def restart(): Unit = { compilerAccess.shutdownCurrentCompiler() } @@ -221,45 +148,9 @@ case class ScalaPresentationCompiler( ) } - private def outlineFiles( - current: VirtualFileParams - ): OutlineFiles = { - val shouldCompileAll = wasSuccessfullyCompiled - .getAndUpdate { - case CompilationStatus.UnSuccessfullyCompiled => - CompilationStatus.OutlinedByPC - case value => value - } == CompilationStatus.UnSuccessfullyCompiled - - val result = - if (shouldCompileAll) { - // if first compilation was unsuccessful we want to outline all files - compilerFiles.iterator.flatMap(_.allPaths().asScala).foreach { path => - val uri = path.toUri() - if (!changedDocuments.contains(uri)) { - val text = Files.readString(path) - changedDocuments += uri -> CompilerOffsetParams(uri, text, 0) - } - } - OutlineFiles( - changedDocuments.values.toList, - firstCompileSubstitute = true - ) - } else { - val files = - changedDocuments.values.filterNot(_.uri() == current.uri()).toList - OutlineFiles(files) - } - - changedDocuments.clear() - changedDocuments += current.uri() -> current - result - } - override def didChange( params: VirtualFileParams ): CompletableFuture[ju.List[Diagnostic]] = { - changedDocuments += params.uri() -> params CompletableFuture.completedFuture(Nil.asJava) } @@ -281,7 +172,7 @@ case class ScalaPresentationCompiler( params.token ) { pc => new PcSemanticTokensProvider( - pc.compiler(outlineFiles(params)), + pc.compiler(params), params ).provide().asJava } @@ -310,7 +201,7 @@ case class ScalaPresentationCompiler( EmptyCompletionList(), params.token ) { pc => - new CompletionProvider(pc.compiler(outlineFiles(params)), params) + new CompletionProvider(pc.compiler(params), params) .completions() } } @@ -323,7 +214,7 @@ case class ScalaPresentationCompiler( empty, params.token ) { pc => - new CompletionProvider(pc.compiler(outlineFiles(params)), params) + new CompletionProvider(pc.compiler(params), params) .implementAll() } } @@ -336,7 +227,7 @@ case class ScalaPresentationCompiler( empty, params.token ) { pc => - new InferredTypeProvider(pc.compiler(outlineFiles(params)), params) + new InferredTypeProvider(pc.compiler(params), params) .inferredTypeEdits() .asJava } @@ -349,7 +240,7 @@ case class ScalaPresentationCompiler( (compilerAccess .withInterruptableCompiler(Some(params))(empty, params.token) { pc => new PcInlineValueProviderImpl( - pc.compiler(outlineFiles(params)), + pc.compiler(params), params ).getInlineTextEdits }) @@ -367,7 +258,7 @@ case class ScalaPresentationCompiler( compilerAccess.withInterruptableCompiler(Some(range))(empty, range.token) { pc => new ExtractMethodProvider( - pc.compiler(outlineFiles(range)), + pc.compiler(range), range, extractionPos ).extractMethod.asJava @@ -382,7 +273,7 @@ case class ScalaPresentationCompiler( (compilerAccess .withInterruptableCompiler(Some(params))(empty, params.token) { pc => new ConvertToNamedArgumentsProvider( - pc.compiler(outlineFiles(params)), + pc.compiler(params), params, argIndices.asScala.map(_.toInt).toSet ).convertToNamedArguments @@ -402,7 +293,7 @@ case class ScalaPresentationCompiler( List.empty[AutoImportsResult].asJava, params.token ) { pc => - new AutoImportsProvider(pc.compiler(outlineFiles(params)), name, params) + new AutoImportsProvider(pc.compiler(params), name, params) .autoImports() .asJava } @@ -434,7 +325,7 @@ case class ScalaPresentationCompiler( new SignatureHelp(), params.token ) { pc => - new SignatureHelpProvider(pc.compiler(outlineFiles(params))) + new SignatureHelpProvider(pc.compiler(params)) .signatureHelp(params) } @@ -445,7 +336,7 @@ case class ScalaPresentationCompiler( Optional.empty[Range](), params.token ) { pc => - new PcRenameProvider(pc.compiler(outlineFiles(params)), params, None) + new PcRenameProvider(pc.compiler(params), params, None) .prepareRename() .asJava } @@ -459,7 +350,7 @@ case class ScalaPresentationCompiler( params.token ) { pc => new PcRenameProvider( - pc.compiler(outlineFiles(params)), + pc.compiler(params), params, Some(name) ).rename().asJava @@ -473,7 +364,7 @@ case class ScalaPresentationCompiler( params.token ) { pc => Optional.ofNullable( - new HoverProvider(pc.compiler(outlineFiles(params)), params) + new HoverProvider(pc.compiler(params), params) .hover() .orNull ) @@ -484,7 +375,7 @@ case class ScalaPresentationCompiler( DefinitionResultImpl.empty, params.token ) { pc => - new PcDefinitionProvider(pc.compiler(outlineFiles(params)), params) + new PcDefinitionProvider(pc.compiler(params), params) .definition() } } @@ -496,7 +387,7 @@ case class ScalaPresentationCompiler( DefinitionResultImpl.empty, params.token ) { pc => - new PcDefinitionProvider(pc.compiler(outlineFiles(params)), params) + new PcDefinitionProvider(pc.compiler(params), params) .typeDefinition() } } @@ -508,7 +399,7 @@ case class ScalaPresentationCompiler( List.empty[DocumentHighlight].asJava, params.token() ) { pc => - new PcDocumentHighlightProvider(pc.compiler(outlineFiles(params)), params) + new PcDocumentHighlightProvider(pc.compiler(params), params) .highlights() .asJava } @@ -518,15 +409,21 @@ case class ScalaPresentationCompiler( code: String ): CompletableFuture[Array[Byte]] = { val virtualFile = CompilerVirtualFileParams(fileUri, code) + semanticdbTextDocument(virtualFile) + } + + override def semanticdbTextDocument( + virtualFile: VirtualFileParams + ): CompletableFuture[Array[Byte]] = { compilerAccess.withInterruptableCompiler(Some(virtualFile))( Array.emptyByteArray, EmptyCancelToken ) { pc => new SemanticdbTextDocumentProvider( - pc.compiler(outlineFiles(CompilerOffsetParams(fileUri, code, 0))), + pc.compiler(virtualFile), config.semanticdbCompilerOptions().asScala.toList ) - .textDocument(fileUri, code) + .textDocument(virtualFile.uri(), virtualFile.text()) .toByteArray } } @@ -604,27 +501,4 @@ case class ScalaPresentationCompiler( .asJava } - override def withWasSuccessfullyCompiled( - wasSuccessful: Boolean - ): PresentationCompiler = { - this.copy(wasSuccessfullyCompiledInitial = Some(wasSuccessful)) - } - -} - -object CompilationStatus { - sealed trait WasSuccessfullyCompiled - case object SuccessfullyCompiled extends WasSuccessfullyCompiled - case object UnSuccessfullyCompiled extends WasSuccessfullyCompiled - case object WaitingForCompilationResult extends WasSuccessfullyCompiled - case object OutlinedByPC extends WasSuccessfullyCompiled - - def fromWasSuccessfullyCompiled( - wasSuccessfullyCompiled: Option[Boolean] - ): WasSuccessfullyCompiled = - wasSuccessfullyCompiled match { - case None => WaitingForCompilationResult - case Some(true) => SuccessfullyCompiled - case Some(false) => UnSuccessfullyCompiled - } } diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/Scala3CompilerWrapper.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/Scala3CompilerWrapper.scala index da2cadf11d5..fc2ecbfb3a4 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/Scala3CompilerWrapper.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/Scala3CompilerWrapper.scala @@ -5,7 +5,7 @@ import dotty.tools.dotc.reporting.StoreReporter class Scala3CompilerWrapper(driver: MetalsDriver) extends CompilerWrapper[StoreReporter, MetalsDriver]: - override def compiler(paths: OutlineFiles): MetalsDriver = driver + override def compiler(): MetalsDriver = driver override def resetReporter(): Unit = val ctx = driver.currentCtx diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala index 7a1582cf92b..df866938127 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala @@ -181,7 +181,7 @@ case class ScalaPresentationCompiler( def shutdown(): Unit = compilerAccess.shutdown() - override def restart(): Unit = + def restart(): Unit = compilerAccess.shutdownCurrentCompiler() def diagnosticsForDebuggingPurposes(): ju.List[String] = diff --git a/mtags/src/main/scala/scala/meta/internal/metals/OffsetParamsUtils.scala b/mtags/src/main/scala/scala/meta/internal/metals/OffsetParamsUtils.scala index 8c449b181df..842e1e71a89 100644 --- a/mtags/src/main/scala/scala/meta/internal/metals/OffsetParamsUtils.scala +++ b/mtags/src/main/scala/scala/meta/internal/metals/OffsetParamsUtils.scala @@ -3,11 +3,13 @@ package scala.meta.internal.metals import java.net.URI import java.net.URISyntaxException import java.nio.file.Paths +import java.util.Optional import scala.meta.inputs.Position import scala.meta.internal.inputs.XtensionInputSyntaxStructure import scala.meta.pc.CancelToken import scala.meta.pc.OffsetParams +import scala.meta.pc.OutlineFiles trait OffsetParamsUtils { protected def syntaxURI(pos: Position): URI = { @@ -25,34 +27,48 @@ trait OffsetParamsUtils { object CompilerRangeParamsUtils extends OffsetParamsUtils { - def offsetOrRange(pos: Position, token: CancelToken): OffsetParams = { + def offsetOrRange( + pos: Position, + token: CancelToken, + outlineFiles: Optional[OutlineFiles] = Optional.empty() + ): OffsetParams = { if (pos.start == pos.end) - CompilerOffsetParamsUtils.fromPos(pos, token) + CompilerOffsetParamsUtils.fromPos(pos, token, outlineFiles) else - CompilerRangeParamsUtils.fromPos(pos, token) + CompilerRangeParamsUtils.fromPos(pos, token, outlineFiles) } - def fromPos(pos: Position, token: CancelToken): CompilerRangeParams = { + def fromPos( + pos: Position, + token: CancelToken, + outlineFiles: Optional[OutlineFiles] = Optional.empty() + ): CompilerRangeParams = { val uri = syntaxURI(pos) CompilerRangeParams( uri, pos.input.text, pos.start, pos.end, - token + token, + outlineFiles ) } } object CompilerOffsetParamsUtils extends OffsetParamsUtils { - def fromPos(pos: Position, token: CancelToken): CompilerOffsetParams = { + def fromPos( + pos: Position, + token: CancelToken, + outlineFiles: Optional[OutlineFiles] = Optional.empty() + ): CompilerOffsetParams = { val uri = syntaxURI(pos) CompilerOffsetParams( uri, pos.input.text, pos.start, - token + token, + outlineFiles ) } } diff --git a/tests/unit/src/test/scala/tests/CompilersLspSuite.scala b/tests/unit/src/test/scala/tests/CompilersLspSuite.scala index 8a2d8d1d866..da4b1c70214 100644 --- a/tests/unit/src/test/scala/tests/CompilersLspSuite.scala +++ b/tests/unit/src/test/scala/tests/CompilersLspSuite.scala @@ -327,12 +327,12 @@ class CompilersLspSuite extends BaseCompletionLspSuite("compilers") { | required: Int | val i: Int = "aaa" | ^^^^^ - |""".stripMargin + |""".stripMargin, ) _ <- assertCompletion( " def bar = foo.bar@@", "bar: String", - filename = Some("a/src/main/scala/c/C.scala") + filename = Some("a/src/main/scala/c/C.scala"), ) } yield () }