diff --git a/documentation-generator/pom.xml b/documentation-generator/pom.xml
index 874623990aa..8b8464f200e 100644
--- a/documentation-generator/pom.xml
+++ b/documentation-generator/pom.xml
@@ -11,7 +11,7 @@
documentation-generator
Picnic :: Error Prone Support :: Documentation Generation
- Extracts data to generate the documentation
+ Extracts data to generate the documentation.
diff --git a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/BugPatternExtractor.java b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/BugPatternExtractor.java
index ac56dc15d0c..dd57423d947 100644
--- a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/BugPatternExtractor.java
+++ b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/BugPatternExtractor.java
@@ -1,5 +1,7 @@
package tech.picnic.errorprone.plugin;
+import static com.google.common.base.Preconditions.checkArgument;
+
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.util.ASTHelpers;
@@ -19,6 +21,7 @@ public BugPatternExtractor() {}
public BugPatternData extract(ClassTree tree, TaskEvent taskEvent) {
ClassSymbol symbol = ASTHelpers.getSymbol(tree);
BugPattern annotation = symbol.getAnnotation(BugPattern.class);
+ checkArgument(annotation != null, "BugPattern annotation must be present");
return BugPatternData.create(
symbol.getQualifiedName().toString(),
diff --git a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationExtractor.java b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationExtractor.java
index 43009035989..09ffde5bd58 100644
--- a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationExtractor.java
+++ b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationExtractor.java
@@ -4,16 +4,16 @@
import com.sun.source.util.TaskEvent;
/**
- * Interface implemented by a class that defines how to extract {@link T} from a given {@link
+ * Interface implemented by a classes that define how to extract {@link T} from a given {@link
* ClassTree}.
*
* @param The resulting type of the data that is extracted.
*/
-public interface DocumentationExtractor {
+interface DocumentationExtractor {
/**
* Extracts and returns an instance of {@link T} using the provided arguments.
*
- * @param tree The {@link ClassTree} to analyse and extract {@link T} from.
+ * @param tree The {@link ClassTree} to analyze and extract {@link T} from.
* @param taskEvent The {@link TaskEvent} containing information about the current state of the
* compilation.
* @return A non-null instance of {@link T}.
@@ -25,7 +25,7 @@ public interface DocumentationExtractor {
* from the given {@link ClassTree tree}.
*
* @param tree The {@link ClassTree} to check whether documentation can be extracted or not.
- * @return {@code true} iff documentation can be extracted
+ * @return {@code true} iff documentation can be extracted.
*/
// XXX: `JavaFileObject` will most likely be added as parameter to help identify other `DocType`s.
boolean canExtract(ClassTree tree);
diff --git a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGenerator.java b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGenerator.java
index f634e406f43..8258ae1e1ba 100644
--- a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGenerator.java
+++ b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGenerator.java
@@ -1,13 +1,15 @@
package tech.picnic.errorprone.plugin;
+import static com.google.common.base.Preconditions.checkArgument;
+
import com.google.auto.service.AutoService;
import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;
import com.sun.tools.javac.api.BasicJavacTask;
/**
- * A compiler {@link Plugin plugin} that analyzes and extracts data from files containing relevant
- * information for documentation purposes.
+ * A compiler {@link Plugin plugin} that analyzes and extracts relevant information for
+ * documentation purposes from processed files.
*/
@AutoService(Plugin.class)
public final class DocumentationGenerator implements Plugin {
@@ -21,6 +23,7 @@ public String getName() {
@Override
public void init(JavacTask javacTask, String... args) {
+ checkArgument(args.length == 1, "Specify one output path");
javacTask.addTaskListener(
new DocumentationGeneratorTaskListener(((BasicJavacTask) javacTask).getContext(), args[0]));
}
diff --git a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListener.java b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListener.java
index f420d3807f1..aea62ea33d4 100644
--- a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListener.java
+++ b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListener.java
@@ -24,33 +24,36 @@
import javax.tools.JavaFileObject;
/**
- * A {@link TaskListener} that identifies files that contain content relevant for in the
- * documentation.
+ * A {@link TaskListener} that identifies and extracts relevant content for documentation and writes
+ * it to disk.
*/
final class DocumentationGeneratorTaskListener implements TaskListener {
- private final Context context;
- private final Path basePath;
- private final ObjectMapper mapper =
+ private static final ObjectMapper MAPPER =
new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
+ private final Context context;
+ private final String path;
+ private Path basePath;
DocumentationGeneratorTaskListener(Context context, String path) {
this.context = context;
+ this.path = path;
+ this.basePath = Paths.get(path);
+ }
- // XXX: Should we extract this method?
- String docsPath = path.substring(path.indexOf('=') + 1) + File.separator + "docs";
- try {
- this.basePath = Files.createDirectories(Paths.get(docsPath));
- } catch (IOException | InvalidPathException e) {
- throw new IllegalStateException(
- String.format("Error while creating directory with path '%s'", docsPath), e);
- }
+ @Override
+ public void started(TaskEvent taskEvent) {
+ createDirectoriesForPath();
}
@Override
public void finished(TaskEvent taskEvent) {
+ if (taskEvent.getKind() != Kind.ANALYZE) {
+ return;
+ }
+
ClassTree classTree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
JavaFileObject sourceFile = taskEvent.getSourceFile();
- if (classTree == null || sourceFile == null || taskEvent.getKind() != Kind.ANALYZE) {
+ if (classTree == null || sourceFile == null) {
return;
}
@@ -59,10 +62,20 @@ public void finished(TaskEvent taskEvent) {
documentationType ->
writeToFile(
documentationType.getDocumentationExtractor().extract(classTree, taskEvent),
- documentationType.getOutputFileNamePrefix(),
+ documentationType.getIdentifier(),
getSimpleClassName(sourceFile.toUri())));
}
+ private void createDirectoriesForPath() {
+ String docsPath = path.substring(path.indexOf('=') + 1) + File.separator + "docs";
+ try {
+ basePath = Files.createDirectories(Paths.get(docsPath));
+ } catch (IOException | InvalidPathException e) {
+ throw new IllegalStateException(
+ String.format("Error while creating directory with path '%s'", docsPath), e);
+ }
+ }
+
// XXX: `JavaFileObject` will most likely be added as parameter to help identify other `DocType`s.
private static Optional getDocumentationType(ClassTree tree) {
return stream(DocumentationType.values())
@@ -74,7 +87,7 @@ private void writeToFile(T data, String fileName, String name) {
File file = basePath.resolve(String.format("%s-%s.json", fileName, name)).toFile();
try (FileWriter fileWriter = new FileWriter(file, UTF_8, /* append= */ true)) {
- mapper.writeValue(fileWriter, data);
+ MAPPER.writeValue(fileWriter, data);
} catch (IOException e) {
throw new IllegalStateException(
String.format("Could not write to file '%s'", file.getPath()), e);
diff --git a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationType.java b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationType.java
index 6bab4da3a21..3c5d444ccf9 100644
--- a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationType.java
+++ b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/DocumentationType.java
@@ -3,18 +3,18 @@
enum DocumentationType {
BUG_PATTERN("bugpattern", new BugPatternExtractor());
- private final String outputFileNamePrefix;
+ private final String identifier;
@SuppressWarnings("ImmutableEnumChecker" /* `DocumentationExtractor` is effectively immutable. */)
private final DocumentationExtractor> docExtractor;
- DocumentationType(String outputFileNamePrefix, DocumentationExtractor> documentationExtractor) {
- this.outputFileNamePrefix = outputFileNamePrefix;
+ DocumentationType(String identifier, DocumentationExtractor> documentationExtractor) {
+ this.identifier = identifier;
this.docExtractor = documentationExtractor;
}
- String getOutputFileNamePrefix() {
- return outputFileNamePrefix;
+ String getIdentifier() {
+ return identifier;
}
DocumentationExtractor> getDocumentationExtractor() {
diff --git a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/package-info.java b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/package-info.java
index c06b5b41bed..79757779024 100644
--- a/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/package-info.java
+++ b/documentation-generator/src/main/java/tech/picnic/errorprone/plugin/package-info.java
@@ -1,6 +1,6 @@
/**
- * A Java compiler plugin that generates documentation by extracting the relevant data from
- * different source files.
+ * Module for the generation of documentation by extracting the relevant data from different source
+ * files.
*/
@com.google.errorprone.annotations.CheckReturnValue
@org.jspecify.annotations.NullMarked
diff --git a/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorBugPatternTest.java b/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorBugPatternTest.java
index 430c4886cba..ce815b2d4b5 100644
--- a/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorBugPatternTest.java
+++ b/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorBugPatternTest.java
@@ -15,7 +15,7 @@
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.io.TempDir;
-final class DocumentationGeneratorBugPatternTest extends DocumentationGeneratorCompilerBasedTest {
+final class DocumentationGeneratorBugPatternTest extends DocumentationGeneratorTaskListenerTest {
@EnabledOnOs(WINDOWS)
@Test
void wrongPathFailsWindows() {
@@ -25,15 +25,15 @@ void wrongPathFailsWindows() {
@DisabledOnOs(WINDOWS)
@Test
void wrongPathFailsOtherOperatingSystems() {
- // Strictly speaking we are validating here that we cannot write to a RO FS.
+ // Strictly speaking we are validating here that we cannot write to a Read-only file system.
wrongPathFails('/');
}
private void wrongPathFails(char invalidCharacter) {
String invalidPath = invalidCharacter + "wrong-path";
assertThatThrownBy(() -> compile(invalidPath))
- .isInstanceOf(IllegalStateException.class)
- .hasMessage(
+ .hasCauseInstanceOf(IllegalStateException.class)
+ .hasMessageEndingWith(
"Error while creating directory with path '%s'", invalidPath + File.separator + "docs");
}
@@ -42,8 +42,7 @@ void noClass(@TempDir Path directory) {
Path outputPath = directory.resolve("pkg").toAbsolutePath();
compile(outputPath.toString(), "package pkg;");
- assertThat(
- outputPath.resolve("docs").resolve("bugpattern-CompilerBasedTestInput.json").toFile())
+ assertThat(outputPath.resolve("docs").resolve("bugpattern-TaskListenerTestInput.json").toFile())
.doesNotExist();
}
@@ -56,8 +55,7 @@ void noJsonExpected(@TempDir Path directory) {
"",
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
- assertThat(
- outputPath.resolve("docs").resolve("bugpattern-CompilerBasedTestInput.json").toFile())
+ assertThat(outputPath.resolve("docs").resolve("bugpattern-TaskListenerTestInput.json").toFile())
.doesNotExist();
}
@@ -77,7 +75,7 @@ void minimalBugPattern(@TempDir Path directory) throws IOException {
assertThat(
Files.readString(
- outputPath.resolve("docs").resolve("bugpattern-CompilerBasedTestInput.json")))
+ outputPath.resolve("docs").resolve("bugpattern-TaskListenerTestInput.json")))
.isEqualToIgnoringWhitespace(getResource("bugpattern_example_minimal_testdata.json"));
}
@@ -106,7 +104,7 @@ void completeBugPattern(@TempDir Path directory) throws IOException {
assertThat(
Files.readString(
- outputPath.resolve("docs").resolve("bugpattern-CompilerBasedTestInput.json")))
+ outputPath.resolve("docs").resolve("bugpattern-TaskListenerTestInput.json")))
.isEqualToIgnoringWhitespace(getResource("bugpattern_example_testdata.json"));
}
diff --git a/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorCompilerBasedTest.java b/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListenerTest.java
similarity index 92%
rename from documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorCompilerBasedTest.java
rename to documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListenerTest.java
index bf4a233ab4e..59fd0f1d7c7 100644
--- a/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorCompilerBasedTest.java
+++ b/documentation-generator/src/test/java/tech/picnic/errorprone/plugin/DocumentationGeneratorTaskListenerTest.java
@@ -18,9 +18,9 @@
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
-abstract class DocumentationGeneratorCompilerBasedTest {
+abstract class DocumentationGeneratorTaskListenerTest {
public void compile(String outputDirectory, String... lines) {
- compile(outputDirectory, FileObjects.forSourceLines("CompilerBasedTestInput.java", lines));
+ compile(outputDirectory, FileObjects.forSourceLines("TaskListenerTestInput.java", lines));
}
private static void compile(String outputDirectory, JavaFileObject javaFileObject) {