Skip to content

Commit

Permalink
move logic outline files logic out of pc
Browse files Browse the repository at this point in the history
  • Loading branch information
kasiaMarek committed Mar 19, 2024
1 parent f31b404 commit 6675382
Show file tree
Hide file tree
Showing 20 changed files with 530 additions and 316 deletions.
303 changes: 204 additions & 99 deletions metals/src/main/scala/scala/meta/internal/metals/Compilers.scala

Large diffs are not rendered by default.

Expand Up @@ -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) =
Option
Expand All @@ -178,8 +180,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,
Expand Down
@@ -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

This file was deleted.

16 changes: 16 additions & 0 deletions 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<VirtualFileParams> files();
}
Expand Up @@ -194,6 +194,14 @@ public CompletableFuture<Optional<PcSymbolInformation>> info(String symbol) {
*/
public abstract CompletableFuture<byte[]> semanticdbTextDocument(URI filename, String code);

/**
* Returns the Protobuf byte array representation of a SemanticDB
* <code>TextDocument</code> for the given source.
*/
public CompletableFuture<byte[]> semanticdbTextDocument(VirtualFileParams params) {
return semanticdbTextDocument(params.uri(), params.text());
}

/**
* Return the selections ranges for the given positions.
*/
Expand All @@ -215,13 +223,6 @@ public CompletableFuture<Optional<PcSymbolInformation>> info(String symbol) {
*/
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.
*/
Expand All @@ -241,13 +242,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.
Expand Down Expand Up @@ -336,8 +330,4 @@ public abstract PresentationCompiler newInstance(String buildTargetIdentifier, L
*/
public abstract String scalaVersion();

public PresentationCompiler withWasSuccessfullyCompiled(boolean wasSuccessful) {
return this;
}

}
@@ -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.
Expand All @@ -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> outlineFiles() {
return Optional.empty();
}

default void checkCanceled() {
token().checkCanceled();
}
Expand Down
@@ -1,30 +1,35 @@
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(
uri: URI,
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
)
}
@@ -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

0 comments on commit 6675382

Please sign in to comment.