Skip to content

Commit e4532cb

Browse files
authored
Add support for Scalafix (#20394)
Implemented for `fix` and `lint` goals.
1 parent 548ef90 commit e4532cb

27 files changed

+5179
-11
lines changed

.scalafix.conf

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
rules = [
2+
NoAutoTupling,
3+
DisableSyntax,
4+
NoValInForComprehension,
5+
RedundantSyntax,
6+
RemoveUnused,
7+
ProcedureSyntax
8+
]
9+
10+
DisableSyntax.noThrows = true

3rdparty/jvm/org/scalameta/BUILD

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
22
# Licensed under the Apache License, Version 2.0 (see LICENSE).
33

4+
scala_artifact(
5+
name="semanticdb-jar",
6+
group="org.scalameta",
7+
artifact="semanticdb-scalac",
8+
version="4.8.4",
9+
resolve="jvm_testprojects",
10+
crossversion="full",
11+
)
12+
13+
scalac_plugin(name="semanticdb", artifact=":semanticdb-jar")
14+
415
# Note: This target must be kept in sync with the requirements in `generate_scala_parser_lockfile_request`.
5-
jvm_artifact(
16+
scala_artifact(
617
name="scalameta",
718
group="org.scalameta",
8-
artifact="scalameta_2.13",
19+
artifact="scalameta",
920
version="4.8.7",
1021
packages=["scala.meta.**"],
1122
resolve="scala_parser_dev",

3rdparty/jvm/testprojects.lockfile

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# This lockfile was autogenerated by Pants. To regenerate, run:
22
#
3-
# ./pants generate-lockfiles
3+
# pants generate-lockfiles
44
#
55
# --- BEGIN PANTS LOCKFILE METADATA: DO NOT EDIT OR REMOVE ---
66
# {
77
# "version": 1,
88
# "generated_with_requirements": [
9-
# "org.scala-lang:scala-library:2.13.6,url=not_provided,jar=not_provided"
9+
# "org.scala-lang:scala-library:2.13.6,url=not_provided,jar=not_provided",
10+
# "org.scalameta:semanticdb-scalac_2.13.6:4.8.4,url=not_provided,jar=not_provided"
1011
# ]
1112
# }
1213
# --- END PANTS LOCKFILE METADATA ---
@@ -24,3 +25,26 @@ packaging = "jar"
2425
[entries.file_digest]
2526
fingerprint = "f19ed732e150d3537794fd3fe42ee18470a3f707efd499ecd05a99e727ff6c8a"
2627
serialized_bytes_length = 5955737
28+
[[entries]]
29+
file_name = "org.scalameta_semanticdb-scalac_2.13.6_4.8.4.jar"
30+
[[entries.directDependencies]]
31+
group = "org.scala-lang"
32+
artifact = "scala-library"
33+
version = "2.13.6"
34+
packaging = "jar"
35+
36+
[[entries.dependencies]]
37+
group = "org.scala-lang"
38+
artifact = "scala-library"
39+
version = "2.13.6"
40+
packaging = "jar"
41+
42+
43+
[entries.coord]
44+
group = "org.scalameta"
45+
artifact = "semanticdb-scalac_2.13.6"
46+
version = "4.8.4"
47+
packaging = "jar"
48+
[entries.file_digest]
49+
fingerprint = "acc1f667d4e98b42ba851309feb391cf301afeeeeddb8c172874a2184b18b057"
50+
serialized_bytes_length = 17073222

docs/docs/jvm/java-and-scala.mdx

+37
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,43 @@ Once enabled, `lint` and `fmt` will check and automatically reformat your code:
312312
❯ pants --changed-since=HEAD fmt
313313
```
314314

315+
### Fix Scala code
316+
317+
Additionally to the previously mentioned tools, `scalafix` can also be enabled by adding the `pants.backend.experimental.scala.lint.scalafix` backend to `backend_packages` in the `[GLOBAL]` section of `pants.toml`. However to take full advantage of it additional settings are required.
318+
319+
If we want to use Scalafix's semantic rules, Scalafix needs to be able to find `.semanticdb` compiled files in our classpath. In versions prior to Scala 3 this is achieved by adding the `semanticdb` scalac plugin to our build. Find which is the right version of it for the Scala version you are using and add the following targets:
320+
321+
```python
322+
scala_artifact(
323+
name="semanticdb-jar",
324+
group="org.scalameta",
325+
artifact="semanticdb-scalac",
326+
version="<SEMANTICDB_VERSION>",
327+
crossversion="full",
328+
)
329+
330+
scalac_plugin(name="semanticdb", artifact=":semanticdb-jar")
331+
```
332+
333+
Now you will need to add the `scalac_plugins` field to your scala targets like in the following:
334+
335+
```python
336+
scala_sources(scalac_plugins=["semanticdb"])
337+
```
338+
339+
Alternatively, you could add `semanticdb` to the `[scalac].plugins_for_resolve` setting:
340+
341+
```toml pants.toml
342+
[scalac.plugins_for_resolve]
343+
jvm-default = "semanticdb"
344+
```
345+
346+
:::note Scalafix and Scala 3
347+
At the moment the support for Scalac 3 in Scalafix is limited, most of the syntactic rules work but not that many in the semantic front.
348+
349+
Despite those raugh edges, Scalafix is a great linting tool for Scala 3, just note that the setup is different than from prior versions: Instead of adding a scalac plugin to our build, we only need to add the `-Xsemanticdb` flag to our `[scalac].args` settings to enable the generation of `.semanticdb` compiled files.
350+
:::
351+
315352
## Working in an IDE
316353

317354
Pants supports loading Java and Scala projects in IntelliJ via the [BSP protocol](https://build-server-protocol.github.io/) (which should ease VSCode support [via Metals](https://scalameta.org/metals/docs/editors/vscode), although it is not yet supported).

pants.toml

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ backend_packages.add = [
3232
"pants.backend.experimental.python.packaging.pyoxidizer",
3333
"pants.backend.experimental.scala",
3434
"pants.backend.experimental.scala.lint.scalafmt",
35+
"pants.backend.experimental.scala.lint.scalafix",
3536
"pants.backend.experimental.scala.debug_goals",
3637
"pants.backend.experimental.tools.workunit_logger",
3738
"pants.backend.experimental.visibility",
@@ -234,5 +235,8 @@ jar_tool_dev = "src/python/pants/jvm/jar_tool/jar_tool.lock"
234235
[scala]
235236
version_for_resolve = { "scala_parser_dev" = "2.13.8" }
236237

238+
[scalac]
239+
args = ["-Yrangepos", "-Xlint:unused"]
240+
237241
[scala-infer]
238242
force_add_siblings_as_dependencies = false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
2+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3+
4+
python_sources()

src/python/pants/backend/experimental/scala/lint/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3+
4+
python_sources()

src/python/pants/backend/experimental/scala/lint/scalafix/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
2+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3+
4+
from pants.backend.experimental.scala.register import rules as all_scala_rules
5+
from pants.backend.scala.lint.scalafix import extra_fields
6+
from pants.backend.scala.lint.scalafix import rules as scalafix_rules
7+
8+
9+
def rules():
10+
return [
11+
*all_scala_rules(),
12+
*scalafix_rules.rules(),
13+
*extra_fields.rules(),
14+
]

src/python/pants/backend/scala/dependency_inference/BUILD

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ python_tests(name="tests", timeout=240)
1010
scala_sources(
1111
name="scala_parser",
1212
resolve="scala_parser_dev",
13-
# TODO: Allow the parser files to be formatted.
13+
# TODO: Allow the parser files to be formatted and linted.
1414
skip_scalafmt=True,
15+
skip_scalafix=True,
1516
)
1617

1718
jvm_artifact(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3+
4+
python_sources(dependencies=[":lockfile"])
5+
6+
python_tests(name="tests", dependencies=[":test-lockfiles"])
7+
8+
resource(name="lockfile", source="scalafix.default.lockfile.txt")
9+
10+
resources(name="test-lockfiles", sources=["*.test.lock"])

src/python/pants/backend/scala/lint/scalafix/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3+
4+
from pants.backend.scala.target_types import SCALA_SOURCES_TARGET_TYPES
5+
from pants.engine.target import BoolField
6+
7+
8+
class SkipScalafixField(BoolField):
9+
alias = "skip_scalafix"
10+
default = False
11+
help = "If true, don't run `scalafix` on this target's code."
12+
13+
14+
def rules():
15+
return [tgt.register_plugin_field(SkipScalafixField) for tgt in SCALA_SOURCES_TARGET_TYPES]

0 commit comments

Comments
 (0)