Skip to content

Commit

Permalink
Don't generate SemanticDB for generated or external sources
Browse files Browse the repository at this point in the history
Previously, we only checked if a source ended with the "scala" extension
before adding it to `SemanticDbInfo`. However, we don't want to generate
SemanticDB files for generated files or external files, because they'll
have the output directory (beginning with `bazel-out`) in their paths,
which isn't guaranteed to be consistent.

Also, tell the SemanticDB compiler plugin to generate SemanticDB outside
of the output JAR, even if we don't want SemanticDB generated for any of
the sources. That way, the output JAR won't include SemanticDB files we
don't want.
  • Loading branch information
Jaden Peterson committed Jan 29, 2025
1 parent 782f590 commit 3723c3a
Showing 3 changed files with 74 additions and 31 deletions.
33 changes: 18 additions & 15 deletions rules/private/phases/phase_semanticdb.bzl
Original file line number Diff line number Diff line change
@@ -5,17 +5,15 @@ load(
_SemanticDbInfo = "SemanticDbInfo",
)

def _semanticdb_directory_from_file(file):
def _semanticdb_directory_from_output_jar(file):
"""
This is janky, but we're limited in what we can do in this function. From the
[documentation](https://bazel.build/rules/lib/builtins/Args#add_all) on `Args#add_all`:
To avoid unintended retention of large analysis-phase data structures into the execution phase,
the `map_each` function must be declared by a top-level `def` statement; it may not be a
nested function closure by default.
Using the path of the output JAR to determine the SemanticDB target root is janky, but the
output directory won't be known at build-time, so we have to use the output JAR path as a proxy.
It should be built under the same configuration as the SemanticDB files, since both are produced
by the same compilation action.
"""

return file.path[:file.path.find("META-INF") - 1]
return "{}/semanticdb".format(file.dirname)

#
# PHASE: semanticdb
@@ -33,7 +31,13 @@ def phase_semanticdb(ctx, g):
outputs = []

for source in ctx.files.srcs:
if source.extension == "scala":
# Generated or external files will have the output directory (beginning with `bazel-out`) in
# their paths, which we don't want because it isn't guaranteed to be consistent
if (
source.extension == "scala" and \
source.is_source and \
source.owner.repo_name == ctx.label.repo_name
):
path = paths.join(
directory_name,
"META-INF",
@@ -44,22 +48,21 @@ def phase_semanticdb(ctx, g):
outputs.append(ctx.actions.declare_file(path))

def add_scalacopts(arguments):
if len(outputs) == 0:
return
output_jar = g.classpaths.jar

if toolchain.scala_configuration.version.startswith("2"):
arguments.add("--compiler_option=-P:semanticdb:failures:error")
arguments.add("--compiler_option_referencing_path=-P:semanticdb:sourceroot:${workDir}")
arguments.add_all(
[outputs[0]],
[output_jar],
format_each = "--compiler_option_referencing_path=-P:semanticdb:targetroot:${path} %s",
map_each = _semanticdb_directory_from_file,
map_each = _semanticdb_directory_from_output_jar,
)
else:
arguments.add_all(
[outputs[0]],
[output_jar],
format_each = "--compiler_option_referencing_path=-semanticdb-target:${path} %s",
map_each = _semanticdb_directory_from_file,
map_each = _semanticdb_directory_from_output_jar,
)

arguments.add("--compiler_option_referencing_path=-sourceroot:${workDir}")
28 changes: 24 additions & 4 deletions tests/plugins/semanticdb/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@rules_java//java:java_library.bzl", "java_library")
load("@rules_scala_annex//rules:register_toolchain.bzl", "register_zinc_toolchain")
load("@rules_scala_annex//rules:scala.bzl", "scala_library")
load("@rules_scala_annex//rules/scala:versions.bzl", "scala_2_13_version", "scala_3_version")
@@ -38,7 +40,6 @@ scala_library(
name = "semanticdb-2_13",
srcs = glob(["*.scala"]),
scala_toolchain_name = "scala_2_13_with_semanticdb",
tags = ["manual"],
)

read_semanticdb_info(
@@ -50,7 +51,6 @@ scala_library(
name = "semanticdb-3",
srcs = glob(["*.scala"]),
scala_toolchain_name = "scala_3_with_semanticdb",
tags = ["manual"],
)

read_semanticdb_info(
@@ -60,7 +60,27 @@ read_semanticdb_info(

scala_library(
name = "semanticdb-empty",
srcs = [],
scala_toolchain_name = "scala_2_13_with_semanticdb",
tags = ["manual"],
)

java_library(
name = "sourcejar-library",
resources = glob(["*.scala"]),
)

copy_file(
name = "sourcejar",
src = ":sourcejar-library",
out = "sourcejar.srcjar",
)

scala_library(
name = "semanticdb-sourcejar",
srcs = [":sourcejar"],
scala_toolchain_name = "scala_2_13_with_semanticdb",
)

read_semanticdb_info(
name = "semanticdb-sourcejar-semanticdb-info",
scala_target = ":semanticdb-sourcejar",
)
44 changes: 32 additions & 12 deletions tests/plugins/semanticdb/test
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ bazel_bin="$(bazel info bazel-bin)"

check_for_semanticdb_files() {
for filename in "A.scala.semanticdb" "B.scala.semanticdb"; do
path="../../bazel-bin/plugins/semanticdb/semanticdb-$1/semanticdb/META-INF/semanticdb/plugins/semanticdb/$filename"
path="../../bazel-bin/plugins/semanticdb/$1/semanticdb/META-INF/semanticdb/plugins/semanticdb/$filename"

if [ ! -f "$path" ]; then
echo "Error: $path doesn't exist"
@@ -15,22 +15,42 @@ check_for_semanticdb_files() {
}

check_semanticdb_info() {
bazel build ":semanticdb-$1-semanticdb-info"
bazel build ":$1-semanticdb-info"

output_path="$bazel_bin/plugins/semanticdb/semanticdb-$1-semanticdb-info.txt"
output_path="$bazel_bin/plugins/semanticdb/$1-semanticdb-info.txt"
reported_semanticdb_files="$(jq -r '.semanticDbFiles[]' "$output_path" | sed -E 's_^bazel-out/[^\n/]+/bin/__g')"
semanticdb_file_directory="plugins/semanticdb/semanticdb-$1/semanticdb/META-INF/semanticdb/plugins/semanticdb"
semanticdb_file_directory="plugins/semanticdb/$1/semanticdb/META-INF/semanticdb/plugins/semanticdb"

[ "$(jq '.targetRoot' "$output_path")" = "\"plugins/semanticdb/semanticdb-$1/semanticdb\"" ]
[ "$(jq '.targetRoot' "$output_path")" = "\"plugins/semanticdb/$1/semanticdb\"" ]
[ "$reported_semanticdb_files" = "$semanticdb_file_directory/A.scala.semanticdb"$'\n'"$semanticdb_file_directory/B.scala.semanticdb" ]
}

bazel build :semanticdb-2_13
check_for_semanticdb_files 2_13
check_semanticdb_info 2_13
works_with_scala_2_13() {
bazel build :semanticdb-2_13
check_for_semanticdb_files semanticdb-2_13
check_semanticdb_info semanticdb-2_13
}

works_with_scala_3() {
bazel build :semanticdb-3
check_for_semanticdb_files semanticdb-3
check_semanticdb_info semanticdb-3
}

works_with_no_sources() {
bazel build :semanticdb-empty
}

does_not_produce_semanticdb_for_source_jars() {
bazel build :sourcejar-library

bazel build :semanticdb-3
check_for_semanticdb_files '3'
check_semanticdb_info '3'
semanticdb_info_path="$bazel_bin/plugins/semanticdb/semanticdb-sourcejar-semanticdb-info.txt"

[ "$(jq '.semanticDbFiles' "$semanticdb_info_path")" = '[]' ]
[ "$(jq '.targetRoot' "$semanticdb_info_path")" = 'plugins/semanticdb/semanticdb-sourcejar/semanticdb' ]
}

bazel build :semanticdb-empty
works_with_scala_2_13
works_with_scala_3
works_with_no_sources
does_not_produce_semanticdb_for_source_jars

0 comments on commit 3723c3a

Please sign in to comment.