Skip to content

Commit

Permalink
Fix diagnostics for Scala 2.13.12 (#1522)
Browse files Browse the repository at this point in the history
* Fix diagnostics for Scala 2.13.12

* Fix sha256sum for org.scalameta:semanticdb-scalac_2_11:4.8.6

* Add Tally as an adopter

* Fix ProtoReporter issue with semanticdb in Scala 2.12.x
  • Loading branch information
scoquelin committed Nov 27, 2023
1 parent 9c0f6b9 commit f938141
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ Here's a (non-exhaustive) list of companies that use `rules_scala` in production
* [Meetup](https://meetup.com/)
* [Spotify](https://www.spotify.com/)
* [Stripe](https://stripe.com/)
* [Tally](https://www.meettally.com/)
* [Twitter](https://twitter.com/)
* [VSCO](https://vsco.co)
* [Wix](https://www.wix.com/)
Expand Down
12 changes: 9 additions & 3 deletions src/java/io/bazel/rulesscala/scalac/reporter/BUILD
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_java//java:defs.bzl", "java_library", "java_proto_library")
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_MAJOR_VERSION")
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_MAJOR_VERSION", "SCALA_MINOR_VERSION")

java_library(
name = "reporter",
srcs = [
"//src/java/io/bazel/rulesscala/scalac/deps_tracking_reporter",
"ProtoReporter.java",
] if SCALA_MAJOR_VERSION.startswith("2") else ["PlaceholderForEmptyScala3Lib.java"],
"before_2_12_13/ProtoReporter.java",
] if SCALA_MAJOR_VERSION.startswith("2.11") or (SCALA_MAJOR_VERSION.startswith("2.12") and int(SCALA_MINOR_VERSION) < 13) else [
"//src/java/io/bazel/rulesscala/scalac/deps_tracking_reporter",
"after_2_12_13_and_before_2_13_12/ProtoReporter.java",
] if ((SCALA_MAJOR_VERSION.startswith("2.12") and int(SCALA_MINOR_VERSION) >= 13) or (SCALA_MAJOR_VERSION.startswith("2.13") and int(SCALA_MINOR_VERSION) < 12)) else [
"//src/java/io/bazel/rulesscala/scalac/deps_tracking_reporter",
"after_2_13_12/ProtoReporter.java",
] if (SCALA_MAJOR_VERSION.startswith("2.13") and int(SCALA_MINOR_VERSION) >= 12) else ["PlaceholderForEmptyScala3Lib.java"],
visibility = ["//visibility:public"],
deps = [
":scala_deps_java_proto",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package io.bazel.rulesscala.scalac.reporter;

import io.bazel.rules_scala.diagnostics.Diagnostics;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import scala.reflect.internal.util.Position;
import scala.reflect.internal.util.RangePosition;
import scala.tools.nsc.Settings;
import scala.tools.nsc.reporters.ConsoleReporter;

public class ProtoReporter extends ConsoleReporter {

private final Map<String, List<Diagnostics.Diagnostic>> builder;

public ProtoReporter(Settings settings) {
super(settings);
builder = new LinkedHashMap<>();
}

@Override
public void reset() {
super.reset();
}

public void writeTo(Path path) throws IOException {
Diagnostics.TargetDiagnostics.Builder targetDiagnostics =
Diagnostics.TargetDiagnostics.newBuilder();
for (Map.Entry<String, List<Diagnostics.Diagnostic>> entry : builder.entrySet()) {
targetDiagnostics.addDiagnostics(
Diagnostics.FileDiagnostics.newBuilder()
.setPath(entry.getKey())
.addAllDiagnostics(entry.getValue()));
}
Files.write(
path,
targetDiagnostics.build().toByteArray(),
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}

@Override
public void info0(Position pos, String msg, Severity severity, boolean force) {
doReport(pos, msg, severity);
}

@Override
public void doReport(Position pos, String msg, Severity severity) {
super.doReport(pos, msg, severity);

Diagnostics.Diagnostic diagnostic =
Diagnostics.Diagnostic.newBuilder()
.setRange(positionToRange(pos))
.setSeverity(convertSeverity(severity))
.setMessage(msg)
.build();
// TODO: Handle generated files
String uri = "workspace-root://" + pos.source().file().path();
List<Diagnostics.Diagnostic> diagnostics = builder.computeIfAbsent(uri, key -> new ArrayList());
diagnostics.add(diagnostic);
}

private Diagnostics.Severity convertSeverity(Object severity) {
String stringified = severity.toString().toLowerCase();
if ("error".equals(stringified)) {
return Diagnostics.Severity.ERROR;
} else if ("warning".equals(stringified)) {
return Diagnostics.Severity.WARNING;
} else if ("info".equals(stringified)) {
return Diagnostics.Severity.INFORMATION;
}
throw new RuntimeException("Unknown severity: " + stringified);
}

private Diagnostics.Range positionToRange(Position pos) {
if (pos instanceof RangePosition) {
RangePosition rangePos = (RangePosition) pos;
int startLine = pos.source().offsetToLine(rangePos.start());
int endLine = pos.source().offsetToLine(rangePos.end());
return Diagnostics.Range.newBuilder()
.setStart(
Diagnostics.Position.newBuilder()
.setLine(startLine)
.setCharacter(rangePos.start() - pos.source().lineToOffset(startLine)))
.setEnd(
Diagnostics.Position.newBuilder()
.setLine(endLine)
.setCharacter(rangePos.end() - pos.source().lineToOffset(endLine))
.build())
.build();
}
return Diagnostics.Range.newBuilder()
.setStart(
Diagnostics.Position.newBuilder()
.setLine(pos.line() - 1)
.setCharacter(pos.column() - 1))
.setEnd(Diagnostics.Position.newBuilder().setLine(pos.line()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package io.bazel.rulesscala.scalac.reporter;

import io.bazel.rules_scala.diagnostics.Diagnostics;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import scala.collection.immutable.List$;
import scala.reflect.internal.util.CodeAction;
import scala.reflect.internal.util.Position;
import scala.reflect.internal.util.RangePosition;
import scala.tools.nsc.Settings;
import scala.tools.nsc.reporters.ConsoleReporter;

public class ProtoReporter extends ConsoleReporter {

private final Map<String, List<Diagnostics.Diagnostic>> builder;

public ProtoReporter(Settings settings) {
super(settings);
builder = new LinkedHashMap<>();
}

@Override
public void reset() {
super.reset();
}

public void writeTo(Path path) throws IOException {
Diagnostics.TargetDiagnostics.Builder targetDiagnostics =
Diagnostics.TargetDiagnostics.newBuilder();
for (Map.Entry<String, List<Diagnostics.Diagnostic>> entry : builder.entrySet()) {
targetDiagnostics.addDiagnostics(
Diagnostics.FileDiagnostics.newBuilder()
.setPath(entry.getKey())
.addAllDiagnostics(entry.getValue()));
}
Files.write(
path,
targetDiagnostics.build().toByteArray(),
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}

@Override
public void doReport(Position pos, String msg, Severity severity, scala.collection.immutable.List<CodeAction> actions) {
super.doReport(pos, msg, severity, List$.MODULE$.<CodeAction>empty());

Diagnostics.Diagnostic diagnostic =
Diagnostics.Diagnostic.newBuilder()
.setRange(positionToRange(pos))
.setSeverity(convertSeverity(severity))
.setMessage(msg)
.build();
// TODO: Handle generated files
String uri = "workspace-root://" + pos.source().file().path();
List<Diagnostics.Diagnostic> diagnostics = builder.computeIfAbsent(uri, key -> new ArrayList());
diagnostics.add(diagnostic);
}

private Diagnostics.Severity convertSeverity(Object severity) {
String stringified = severity.toString().toLowerCase();
if ("error".equals(stringified)) {
return Diagnostics.Severity.ERROR;
} else if ("warning".equals(stringified)) {
return Diagnostics.Severity.WARNING;
} else if ("info".equals(stringified)) {
return Diagnostics.Severity.INFORMATION;
}
throw new RuntimeException("Unknown severity: " + stringified);
}

private Diagnostics.Range positionToRange(Position pos) {
if (pos instanceof RangePosition) {
RangePosition rangePos = (RangePosition) pos;
int startLine = pos.source().offsetToLine(rangePos.start());
int endLine = pos.source().offsetToLine(rangePos.end());
return Diagnostics.Range.newBuilder()
.setStart(
Diagnostics.Position.newBuilder()
.setLine(startLine)
.setCharacter(rangePos.start() - pos.source().lineToOffset(startLine)))
.setEnd(
Diagnostics.Position.newBuilder()
.setLine(endLine)
.setCharacter(rangePos.end() - pos.source().lineToOffset(endLine))
.build())
.build();
}
return Diagnostics.Range.newBuilder()
.setStart(
Diagnostics.Position.newBuilder()
.setLine(pos.line() - 1)
.setCharacter(pos.column() - 1))
.setEnd(Diagnostics.Position.newBuilder().setLine(pos.line()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package io.bazel.rulesscala.scalac.reporter;

import io.bazel.rules_scala.diagnostics.Diagnostics;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import scala.reflect.internal.util.Position;
import scala.reflect.internal.util.RangePosition;
import scala.tools.nsc.Settings;
import scala.tools.nsc.reporters.ConsoleReporter;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ProtoReporter extends ConsoleReporter {

private final Map<String, List<Diagnostics.Diagnostic>> builder;
Expand Down
6 changes: 5 additions & 1 deletion test/diagnostics_reporter/BUILD
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
load("@rules_java//java:defs.bzl", "java_binary")
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_MAJOR_VERSION", "SCALA_MINOR_VERSION")

java_binary(
name = "diagnostics_reporter_test",
srcs = [
"DiagnosticsReporterTest.java",
"before_2_13_12/DiagnosticsReporterTest.java",
"VerifyDiagnosticsOutput.java",
] if SCALA_MAJOR_VERSION.startswith("2.11") or SCALA_MAJOR_VERSION.startswith("2.12") or (SCALA_MAJOR_VERSION.startswith("2.13") and int(SCALA_MINOR_VERSION) < 12) else [
"after_2_13_12/DiagnosticsReporterTest.java",
"VerifyDiagnosticsOutput.java",
],
main_class = "diagnostics_reporter.DiagnosticsReporterTest",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package diagnostics_reporter;

import io.bazel.rules_scala.diagnostics.Diagnostics;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DiagnosticsReporterTest {
@SuppressWarnings("DoubleBraceInitialization")
private static final Map<String, diagnostics_reporter.VerifyDiagnosticsOutput[]> tests =
new HashMap<String, diagnostics_reporter.VerifyDiagnosticsOutput[]>() {
{
put(
"error_file",
new diagnostics_reporter.VerifyDiagnosticsOutput[] {
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.ERROR, 5, 2, 6, 0)
});
put(
"two_errors_file",
new diagnostics_reporter.VerifyDiagnosticsOutput[] {
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.ERROR, 4, 4, 4, 10),
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.ERROR, 5, 4, 5, 9)
});
put(
"warning_file",
new diagnostics_reporter.VerifyDiagnosticsOutput[] {
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.WARNING, 0, 0, 0, 26)
});
put(
"error_and_warning_file",
new diagnostics_reporter.VerifyDiagnosticsOutput[] {
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.WARNING, 0, 0, 0, 26),
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.ERROR, 4, 4, 4, 10)
});
put(
"info_file",
new diagnostics_reporter.VerifyDiagnosticsOutput[] {
new diagnostics_reporter.VerifyDiagnosticsOutput(
Diagnostics.Severity.INFORMATION, -1, -1, 0, 0)
});
}
};

public static void main(String[] args) throws IOException {
if (args.length != 1) throw new IllegalArgumentException("Args: <diagnostics_output>");

String diagnosticsOutput = args[0];
for (Map.Entry<String, VerifyDiagnosticsOutput[]> entry : tests.entrySet()) {
String test = entry.getKey();
VerifyDiagnosticsOutput[] expectedDiagnosticsOutputs = entry.getValue();
List<Diagnostics.Diagnostic> diagnostics =
VerifyDiagnosticsOutput.getDiagnostics(
diagnosticsOutput + "/" + test + ".diagnosticsproto");
for (VerifyDiagnosticsOutput expectedDiagnostic : expectedDiagnosticsOutputs) {
expectedDiagnostic.testOutput(diagnostics);
}
}
}
}
12 changes: 12 additions & 0 deletions test_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ test_reporter() {
run_in_test_repo "compilation_should_fail build //... --repo_env=SCALA_VERSION=${SCALA_VERSION} --extra_toolchains=${SCALA_TOOLCHAIN}" "reporter" "test_reporter/"
}

test_diagnostic_proto_files() {
local SCALA_VERSION="$1"
local SCALA_TOOLCHAIN="$2"

compilation_should_fail build --build_event_publish_all_actions -k --repo_env=SCALA_VERSION=${SCALA_VERSION} --extra_toolchains=${SCALA_TOOLCHAIN} //test_expect_failure/diagnostics_reporter:all
diagnostics_output="$(bazel info bazel-bin)/test_expect_failure/diagnostics_reporter"
bazel run --repo_env=SCALA_VERSION=${SCALA_VERSION} //test/diagnostics_reporter:diagnostics_reporter_test "$diagnostics_output"
}

test_twitter_scrooge_versions() {
local version_under_test=$1

Expand Down Expand Up @@ -111,3 +120,6 @@ TEST_TIMEOUT=15 $runner test_reporter "${scala_2_13_version}" "${no_diagnostics_
TEST_TIMEOUT=15 $runner test_reporter "${scala_2_11_version}" "${diagnostics_reporter_toolchain}"
TEST_TIMEOUT=15 $runner test_reporter "${scala_2_12_version}" "${diagnostics_reporter_toolchain}"
TEST_TIMEOUT=15 $runner test_reporter "${scala_2_13_version}" "${diagnostics_reporter_toolchain}"

TEST_TIMEOUT=15 $runner test_diagnostic_proto_files "${scala_2_12_version}" "//test_expect_failure/diagnostics_reporter:diagnostics_reporter_toolchain"
TEST_TIMEOUT=15 $runner test_diagnostic_proto_files "${scala_2_13_version}" "//test_expect_failure/diagnostics_reporter:diagnostics_reporter_toolchain"
2 changes: 1 addition & 1 deletion third_party/repositories/scala_2_11.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ artifacts = {
},
"org_scalameta_semanticdb_scalac": {
"artifact": "org.scalameta:semanticdb-scalac_%s:4.8.6" % scala_version,
"sha256": "1253abd1e8c8b3ec0720995d378846bbc439d168e7ea815fe91da6bef8b1de9d",
"sha256": "5700b0b425eac8e1d0c27660ae96879ef688731cc0d2f2e8cdc7e20496f87670",
"deps": [
"@io_bazel_rules_scala_scala_library",
],
Expand Down

0 comments on commit f938141

Please sign in to comment.