Repository: pantsbuild/pants

Issue:
BSP: Ensure that Scala compiler plugins are detected by the frontend
Currently, we do not expose any of `scalac`'s arguments via the `buildTarget/scalacOptions` message:
https://github.com/pantsbuild/pants/blob/be411561c0ea282c6557854e3519d07a26354b79/src/python/pants/backend/scala/bsp/rules.py#L377

It's likely (although I'm [attempting to confirm upstream](https://discord.com/channels/931170831139217469/931171260824707072/979125460275458119)), that correctly exposing the arguments (including plugin instantion arguments: [computed here](https://github.com/pantsbuild/pants/blob/be411561c0ea282c6557854e3519d07a26354b79/src/python/pants/backend/scala/compile/scalac.py#L180-L188)) would be sufficient for this detection.


Discussion:

Resolving patch:
diff --git a/src/python/pants/backend/scala/bsp/rules.py b/src/python/pants/backend/scala/bsp/rules.py
--- a/src/python/pants/backend/scala/bsp/rules.py
+++ b/src/python/pants/backend/scala/bsp/rules.py
@@ -19,7 +19,14 @@
     ScalaTestClassesParams,
     ScalaTestClassesResult,
 )
+from pants.backend.scala.compile.scalac_plugins import (
+    ScalaPlugins,
+    ScalaPluginsForTargetRequest,
+    ScalaPluginsRequest,
+    ScalaPluginTargetsForTarget,
+)
 from pants.backend.scala.subsystems.scala import ScalaSubsystem
+from pants.backend.scala.subsystems.scalac import Scalac
 from pants.backend.scala.target_types import ScalaFieldSet, ScalaSourceField
 from pants.backend.scala.util_rules.versions import (
     ScalaArtifactsForVersionRequest,
@@ -334,9 +341,7 @@ class HandleScalacOptionsResult:
 
 @_uncacheable_rule
 async def handle_bsp_scalac_options_request(
-    request: HandleScalacOptionsRequest,
-    build_root: BuildRoot,
-    workspace: Workspace,
+    request: HandleScalacOptionsRequest, build_root: BuildRoot, workspace: Workspace, scalac: Scalac
 ) -> HandleScalacOptionsResult:
     targets = await Get(Targets, BuildTargetIdentifier, request.bsp_target_id)
     thirdparty_modules = await Get(
@@ -344,15 +349,30 @@ async def handle_bsp_scalac_options_request(
     )
     resolve = thirdparty_modules.resolve
 
-    resolve_digest = await Get(
-        Digest, AddPrefix(thirdparty_modules.merged_digest, f"jvm/resolves/{resolve.name}/lib")
+    scalac_plugin_targets = await MultiGet(
+        Get(ScalaPluginTargetsForTarget, ScalaPluginsForTargetRequest(tgt, resolve.name))
+        for tgt in targets
+    )
+
+    local_plugins_prefix = f"jvm/resolves/{resolve.name}/plugins"
+    local_plugins = await Get(
+        ScalaPlugins, ScalaPluginsRequest.from_target_plugins(scalac_plugin_targets, resolve)
+    )
+
+    thirdparty_modules_prefix = f"jvm/resolves/{resolve.name}/lib"
+    thirdparty_modules_digest, local_plugins_digest = await MultiGet(
+        Get(Digest, AddPrefix(thirdparty_modules.merged_digest, thirdparty_modules_prefix)),
+        Get(Digest, AddPrefix(local_plugins.classpath.digest, local_plugins_prefix)),
     )
 
+    resolve_digest = await Get(
+        Digest, MergeDigests([thirdparty_modules_digest, local_plugins_digest])
+    )
     workspace.write_digest(resolve_digest, path_prefix=".pants.d/bsp")
 
     classpath = tuple(
         build_root.pathlib_path.joinpath(
-            f".pants.d/bsp/jvm/resolves/{resolve.name}/lib/{filename}"
+            f".pants.d/bsp/{thirdparty_modules_prefix}/{filename}"
         ).as_uri()
         for cp_entry in thirdparty_modules.entries.values()
         for filename in cp_entry.filenames
@@ -361,7 +381,7 @@ async def handle_bsp_scalac_options_request(
     return HandleScalacOptionsResult(
         ScalacOptionsItem(
             target=request.bsp_target_id,
-            options=(),
+            options=(*local_plugins.args(local_plugins_prefix), *scalac.args),
             classpath=classpath,
             class_directory=build_root.pathlib_path.joinpath(
                 f".pants.d/bsp/{jvm_classes_directory(request.bsp_target_id)}"


Test patch: