From 6d60d8374900e6e6f373cbe933e3729791379df5 Mon Sep 17 00:00:00 2001 From: Ashley <73482956+ascopes@users.noreply.github.com> Date: Sat, 14 Jan 2023 10:29:22 +0000 Subject: [PATCH] Change diagnostic repr underline style New style should highlight code like so: 123 | public static void main(String[] args) { + ^~~~~^ Signed-off-by: Ashley <73482956+ascopes@users.noreply.github.com> --- README.md | 121 ++++++++++-------- .../repr/TraceDiagnosticRepresentation.java | 11 +- .../TraceDiagnosticRepresentationTest.java | 26 ++-- 3 files changed, 89 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 7d3d8c2dc..0d9b94606 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,60 @@ Full JUnit5 integration is provided to help streamline the development process. **This module is still under development.** Any contributions or feedback are always welcome! +## Features + +- Implements in-memory file management compatible with the NIO Path and + FileSystem API, enabling tests to run without write access to the host + system, and without awkward resource-cleanup logic. +- Ability to run compilation on combinations of real files, class path + resources, and in-memory files. +- Supports Java 9 JPMS modules as intended. +- Ability to customise a large assortment of configuration parameters + to enable you to test exactly what you need to test. +- Provides support for `javac` out of the box, with the + ability to support other JSR-199 implementations if desired -- + just make use of one of the compiler classes, or make your own! +- Implements a fully functional JSR-199 Path JavaFileManager. +- Fluent syntax for creating configurations, executing them, and + inspecting the results. +- Integration with AssertJ for fluent assertions on compilation + results. +- Ability to have multiple source roots, just like when using + `javac` normally. +- Diagnostic reporting includes stacktraces, so you can find out + exactly what triggered a diagnostic and begin debugging any + issues in your applications quickly. +- Helpful error messages to assist in annotation processor development + +``` +[main] ERROR io.github.ascopes.jct.diagnostics.TracingDiagnosticListener - cannot find symbol + symbol: class Generated + location: package javax.annotation +[main] INFO io.github.ascopes.jct.compilers.CompilationFactory - Compilation with compiler Javac 9 failed after ~332.3ms + +java.lang.AssertionError: Expected a successful compilation, but it failed. + +Diagnostics: + + - [ERROR] compiler.err.cant.resolve.location /sources-f1728706-5de5-4b89-9a6a-b51233ce67c8/io/github/ascopes/jct/examples/immutables/dataclass/ImmutableAnimal.java (at line 25, col 18) + + 23 | @SuppressWarnings({"all"}) + 24 | @ParametersAreNonnullByDefault + 25 | @javax.annotation.Generated("org.immutables.processor.ProxyProcessor") + + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ + 26 | @Immutable + 27 | @CheckReturnValue + + cannot find symbol + symbol: class Generated + location: package javax.annotation + + at io.github.ascopes.jct.acceptancetests.immutables.ImmutablesIntegrationTest.immutablesValueProducesTheExpectedClass(ImmutablesIntegrationTest.java:66) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:577) + ... +``` + ## Installation The project can be found on Maven Central. @@ -63,6 +117,19 @@ dependencies { } ``` +## JPMS + +If your tests make use of JPMS (i.e. they have a `module-info.java` somewhere), then you will want +to add a requirement for this module like so: + +```java +open module my.tests { + ... + requires io.github.ascopes.jct; + ... +} +``` + ## Examples ### In-memory code, using RAM disks for source directories @@ -234,60 +301,6 @@ class ExampleTest { } ``` -## Features - -- Implements in-memory file management compatible with the NIO Path and - FileSystem API, enabling tests to run without write access to the host - system, and without awkward resource-cleanup logic. -- Ability to run compilation on combinations of real files, class path - resources, and in-memory files. -- Supports Java 9 JPMS modules as intended. -- Ability to customise a large assortment of configuration parameters - to enable you to test exactly what you need to test. -- Provides support for `javac` out of the box, with the - ability to support other JSR-199 implementations if desired -- - just make use of one of the compiler classes, or make your own! -- Implements a fully functional JSR-199 Path JavaFileManager. -- Fluent syntax for creating configurations, executing them, and - inspecting the results. -- Integration with AssertJ for fluent assertions on compilation - results. -- Ability to have multiple source roots, just like when using - `javac` normally. -- Diagnostic reporting includes stacktraces, so you can find out - exactly what triggered a diagnostic and begin debugging any - issues in your applications quickly. -- Helpful error messages to assist in annotation processor development - -``` -[main] ERROR io.github.ascopes.jct.diagnostics.TracingDiagnosticListener - cannot find symbol - symbol: class Generated - location: package javax.annotation -[main] INFO io.github.ascopes.jct.compilers.CompilationFactory - Compilation with compiler Javac 9 failed after ~332.3ms - -java.lang.AssertionError: Expected a successful compilation, but it failed. - -Diagnostics: - - - [ERROR] compiler.err.cant.resolve.location /sources-f1728706-5de5-4b89-9a6a-b51233ce67c8/io/github/ascopes/jct/examples/immutables/dataclass/ImmutableAnimal.java (at line 25, col 18) - - 23 | @SuppressWarnings({"all"}) - 24 | @ParametersAreNonnullByDefault - 25 | @javax.annotation.Generated("org.immutables.processor.ProxyProcessor") - + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 26 | @Immutable - 27 | @CheckReturnValue - - cannot find symbol - symbol: class Generated - location: package javax.annotation - - at io.github.ascopes.jct.acceptancetests.immutables.ImmutablesIntegrationTest.immutablesValueProducesTheExpectedClass(ImmutablesIntegrationTest.java:66) - at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) - at java.base/java.lang.reflect.Method.invoke(Method.java:577) - ... -``` - ## ECJ support While this module initially supported ECJ, there were a number of problems relating to bugs diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/repr/TraceDiagnosticRepresentation.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/repr/TraceDiagnosticRepresentation.java index 4824e0025..4073386cc 100644 --- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/repr/TraceDiagnosticRepresentation.java +++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/repr/TraceDiagnosticRepresentation.java @@ -260,8 +260,15 @@ private void appendPossibleUnderline(StringBuilder builder, int startOfLine, int .append(" ".repeat(lineNumberWidth)) .append(" + "); - for (int i = startOfLine; i < Math.min(endOfLine, endOffset); ++i) { - builder.append(startOffset <= i ? '^' : ' '); + var endIndex = Math.min(endOfLine, endOffset); + for (int i = startOfLine; i < endIndex; ++i) { + if (i < startOffset) { + builder.append(' '); + } else if (i == startOffset || i == endOffset - 1) { + builder.append('^'); + } else { + builder.append('~'); + } } builder.append('\n'); diff --git a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/repr/TraceDiagnosticRepresentationTest.java b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/repr/TraceDiagnosticRepresentationTest.java index e75ed1ef5..bb11f7167 100644 --- a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/repr/TraceDiagnosticRepresentationTest.java +++ b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/repr/TraceDiagnosticRepresentationTest.java @@ -45,7 +45,6 @@ * @author Ashley Scopes */ @DisplayName("TraceDiagnosticRepresentation tests") -@SuppressWarnings("NullableProblems") class TraceDiagnosticRepresentationTest { @TempDir @@ -132,7 +131,7 @@ void toStringOfTraceDiagnosticRendersTheDiagnosticWhenFileContentsArePresentViaG " 4 | ", " 5 | public class HelloWorld {", " 6 | public static int main(String[] args) throws Throwable {", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^", " 7 | var scanner = new Scanner(System.in);", " 8 | System.out.print(\"What is your name? \");", "", @@ -184,7 +183,7 @@ void toStringOfTraceDiagnosticRendersTheDiagnosticWhenFileContentsArePresentViaO " 4 | ", " 5 | public class HelloWorld {", " 6 | public static int main(String[] args) throws Throwable {", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^", " 7 | var scanner = new Scanner(System.in);", " 8 | System.out.print(\"What is your name? \");", "", @@ -236,7 +235,7 @@ void toStringOfTraceDiagnosticRendersDiagnosticWhenGetCharContentReturnsNullViaO " 4 | ", " 5 | public class HelloWorld {", " 6 | public static int main(String[] args) throws Throwable {", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^", " 7 | var scanner = new Scanner(System.in);", " 8 | System.out.print(\"What is your name? \");", "", @@ -327,9 +326,9 @@ void toStringOfRendersMultilineSnippetsCorrectly() { " 4 | ", " 5 | public class HelloWorld {", " 6 | public static int main(String[] args) throws Throwable {", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", " 7 | var scanner = new Scanner(System.in);", - " + ^^^^^^^^^^^^^^^", + " + ~~~~~~~~~~~~~~^", " 8 | System.out.print(\"What is your name? \");", " 9 | var name = scanner.nextLine();", "", @@ -373,25 +372,26 @@ void toStringOfRendersMultilineSnippetsCorrectlyWithErroneousEndPositions() { " 4 | ", " 5 | public class HelloWorld {", " 6 | public static int main(String[] args) throws Throwable {", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", " 7 | var scanner = new Scanner(System.in);", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", " 8 | System.out.print(\"What is your name? \");", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", " 9 | var name = scanner.nextLine();", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", " 10 | System.out.printf(\"Hello, %s!\", name);", - " + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", " 11 | }", - " + ^^^", + " + ~~~", " 12 | }", - " + ^", + " + ~", "", " Entrypoint must be a void method." ); } @DisplayName("toStringOf(TraceDiagnostic) renders the diagnostic when source is not present") + @SuppressWarnings("DataFlowIssue") @Test void toStringOfTraceDiagnosticRendersTheDiagnosticWhenSourceIsNotPresent() { // Given