Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Scala/Java version agnostic option for setting the SemanticDB target root and source root directories #2692

Merged
merged 4 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions modules/build/src/main/scala/scala/build/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,11 @@ object Build {
val classesDir0 = classesDir(inputs.workspace, inputs.projectName, scope)
val scaladocDir = classesDir(inputs.workspace, inputs.projectName, scope, suffix = "-doc")

val generateSemanticDbs = options.scalaOptions.generateSemanticDbs.getOrElse(false)
val generateSemanticDbs =
options.scalaOptions.semanticDbOptions.generateSemanticDbs.getOrElse(false)
val semanticDbTargetRoot = options.scalaOptions.semanticDbOptions.semanticDbTargetRoot
val semanticDbSourceRoot =
options.scalaOptions.semanticDbOptions.semanticDbSourceRoot.getOrElse(inputs.workspace)

val releaseFlagVersion = releaseFlag(options, compilerJvmVersionOpt, logger).map(_.toString)

Expand All @@ -842,21 +846,25 @@ object Build {
ScalacOpt(s"-Xplugin:$path")
}

val semanticDbScalacOptions =
if (generateSemanticDbs)
if (params.scalaVersion.startsWith("2."))
Seq(
"-Yrangepos",
"-P:semanticdb:failures:warning",
"-P:semanticdb:synthetics:on",
s"-P:semanticdb:sourceroot:${inputs.workspace}"
).map(ScalacOpt(_))
else
Seq(
"-Xsemanticdb",
"-sourceroot",
inputs.workspace.toString
).map(ScalacOpt(_))
val semanticDbTargetRootOptions: Seq[ScalacOpt] =
(semanticDbTargetRoot match
case Some(targetRoot) if params.scalaVersion.startsWith("2.") =>
Seq(s"-P:semanticdb:targetroot:$targetRoot")
case Some(targetRoot) => Seq("-semanticdb-target", targetRoot.toString)
case None => Nil
).map(ScalacOpt(_))
val semanticDbScalacOptions: Seq[ScalacOpt] =
if generateSemanticDbs then
semanticDbTargetRootOptions ++ (
if params.scalaVersion.startsWith("2.") then
Seq(
"-Yrangepos",
"-P:semanticdb:failures:warning",
"-P:semanticdb:synthetics:on",
s"-P:semanticdb:sourceroot:$semanticDbSourceRoot"
)
else Seq("-Xsemanticdb", "-sourceroot", semanticDbSourceRoot.toString)
).map(ScalacOpt(_))
else Nil

val sourceRootScalacOptions =
Expand Down Expand Up @@ -922,9 +930,10 @@ object Build {
Seq("-J--add-exports", s"-Jjdk.compiler/$pkg=ALL-UNNAMED")
}

val javacTargetRoot = semanticDbTargetRoot.getOrElse("javac-classes-directory")
Seq(
// does the path need to be escaped somehow?
s"-Xplugin:semanticdb -sourceroot:${inputs.workspace} -targetroot:javac-classes-directory"
s"-Xplugin:semanticdb -sourceroot:$semanticDbSourceRoot -targetroot:$javacTargetRoot"
) ++ exports
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ abstract class BuildTests(server: Boolean) extends TestUtil.ScalaCliBuildSuite {
val testInputs = TestInputs(os.rel / "simple.sc" -> scriptContents)
val buildOptions = defaultOptions.copy(
scalaOptions = defaultOptions.scalaOptions.copy(
generateSemanticDbs = Some(true)
semanticDbOptions = defaultOptions.scalaOptions.semanticDbOptions.copy(
generateSemanticDbs = Some(true)
)
)
)
testInputs.withBuild(buildOptions, buildThreads, bloopConfigOpt) { (_, _, maybeBuild) =>
Expand Down Expand Up @@ -227,7 +229,9 @@ abstract class BuildTests(server: Boolean) extends TestUtil.ScalaCliBuildSuite {
)
val buildOptions = defaultScala3Options.copy(
scalaOptions = defaultScala3Options.scalaOptions.copy(
generateSemanticDbs = Some(true)
semanticDbOptions = defaultScala3Options.scalaOptions.semanticDbOptions.copy(
generateSemanticDbs = Some(true)
)
)
)
testInputs.withBuild(buildOptions, buildThreads, bloopConfigOpt) { (_, _, maybeBuild) =>
Expand Down
5 changes: 4 additions & 1 deletion modules/cli/src/main/scala/scala/cli/commands/bsp/Bsp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ object Bsp extends ScalaCommand[BspOptions] {
fetchSources = baseOptions.classPathOptions.fetchSources.orElse(Some(true))
),
scalaOptions = baseOptions.scalaOptions.copy(
generateSemanticDbs = baseOptions.scalaOptions.generateSemanticDbs.orElse(Some(true))
semanticDbOptions = baseOptions.scalaOptions.semanticDbOptions.copy(
generateSemanticDbs =
baseOptions.scalaOptions.semanticDbOptions.generateSemanticDbs.orElse(Some(true))
)
),
notForBloopOptions = baseOptions.notForBloopOptions.copy(
addRunnerDependencyOpt =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package scala.cli.commands.shared

import caseapp.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import com.github.plokhotnyuk.jsoniter_scala.macros.*

import scala.cli.commands.tags

case class SemanticDbOptions(
@Hidden
@Tag(tags.should)
@HelpMessage("Generate SemanticDBs")
@Name("semanticdb")
semanticDb: Option[Boolean] = None,
@Hidden
@Tag(tags.should)
@HelpMessage("SemanticDB target root (default to the compiled classes destination directory)")
@Name("semanticdbTargetRoot")
@Name("semanticdbTargetroot")
semanticDbTargetRoot: Option[String] = None,
@Hidden
@Tag(tags.should)
@HelpMessage("SemanticDB source root (default to the project root directory)")
@Name("semanticdbSourceRoot")
@Name("semanticdbSourceroot")
semanticDbSourceRoot: Option[String] = None
)

object SemanticDbOptions {
implicit lazy val parser: Parser[SemanticDbOptions] = Parser.derive
implicit lazy val help: Help[SemanticDbOptions] = Help.derive
implicit lazy val jsonCodec: JsonValueCodec[SemanticDbOptions] = JsonCodecMaker.make
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,8 @@ final case class SharedOptions(
@Hidden
runner: Option[Boolean] = None,

@Hidden
@Tag(tags.should)
@HelpMessage("Generate SemanticDBs")
semanticDb: Option[Boolean] = None,
@Recurse
semanticDbOptions: SemanticDbOptions = SemanticDbOptions(),

@Recurse
input: SharedInputOptions = SharedInputOptions(),
Expand Down Expand Up @@ -360,7 +358,11 @@ final case class SharedOptions(
scalaBinaryVersion = scalaBinaryVersion.map(_.trim).filter(_.nonEmpty),
addScalaLibrary = scalaLibrary.orElse(java.map(!_)),
addScalaCompiler = withCompiler,
generateSemanticDbs = semanticDb,
semanticDbOptions = bo.SemanticDbOptions(
generateSemanticDbs = semanticDbOptions.semanticDb,
semanticDbTargetRoot = semanticDbOptions.semanticDbTargetRoot.map(os.Path(_, os.pwd)),
semanticDbSourceRoot = semanticDbOptions.semanticDbSourceRoot.map(os.Path(_, os.pwd))
),
scalacOptions = scalac
.scalacOption
.withScalacExtraOptions(scalacExtra)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import scala.cli.integration.util.BloopUtil
abstract class CompileTestDefinitions(val scalaVersionOpt: Option[String])
extends ScalaCliSuite
with TestScalaVersionArgs
with CompilerPluginTestDefinitions {
with CompilerPluginTestDefinitions
with SemanticDbTestDefinitions {

protected lazy val extraOptions: Seq[String] = scalaVersionArgs ++ TestUtil.extraOptions

Expand Down Expand Up @@ -467,80 +468,6 @@ abstract class CompileTestDefinitions(val scalaVersionOpt: Option[String])
}
}

test("Manual javac SemanticDB") {
val inputs = TestInputs(
os.rel / "foo" / "Test.java" ->
"""package foo;
|
|public class Test {
| public static void main(String[] args) {
| System.err.println("Hello");
| }
|}
|""".stripMargin
)
inputs.fromRoot { root =>
val compilerPackages = Seq(
"com.sun.tools.javac.api",
"com.sun.tools.javac.code",
"com.sun.tools.javac.model",
"com.sun.tools.javac.tree",
"com.sun.tools.javac.util"
)
val exports = compilerPackages
.flatMap { pkg =>
Seq("-J--add-exports", s"-Jjdk.compiler/$pkg=ALL-UNNAMED")
}
.flatMap(opt => List("--javac-opt", opt))
val javaSemDbOptions = Seq(
"--javac-plugin",
"com.sourcegraph:semanticdb-javac:0.7.4",
"--javac-opt",
s"-Xplugin:semanticdb -sourceroot:$root -targetroot:javac-classes-directory"
) ++ exports
os.proc(TestUtil.cli, "compile", extraOptions, javaSemDbOptions, ".")
.call(cwd = root)

val files = os.walk(root / Constants.workspaceDirName)
val semDbFiles = files
.filter(_.last.endsWith(".semanticdb"))
.filter(!_.segments.exists(_ == "bloop-internal-classes"))
expect(semDbFiles.length == 1)
val semDbFile = semDbFiles.head
expect(
semDbFile.endsWith(os.rel / "META-INF" / "semanticdb" / "foo" / "Test.java.semanticdb")
)
}
}

test("Javac SemanticDB") {
val inputs = TestInputs(
os.rel / "foo" / "Test.java" ->
"""package foo;
|
|public class Test {
| public static void main(String[] args) {
| System.err.println("Hello");
| }
|}
|""".stripMargin
)
inputs.fromRoot { root =>
os.proc(TestUtil.cli, "compile", extraOptions, "--semantic-db", ".")
.call(cwd = root)

val files = os.walk(root / Constants.workspaceDirName)
val semDbFiles = files
.filter(_.last.endsWith(".semanticdb"))
.filter(!_.segments.exists(_ == "bloop-internal-classes"))
expect(semDbFiles.length == 1)
val semDbFile = semDbFiles.head
expect(
semDbFile.endsWith(os.rel / "META-INF" / "semanticdb" / "foo" / "Test.java.semanticdb")
)
}
}

if (actualScalaVersion.startsWith("3"))
test("generate scoverage.coverage file") {
val fileName = "Hello.scala"
Expand Down
Loading