Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Javadoc parser submodule #4748

Merged
merged 65 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
532bc57
Grube!
I-Al-Istannen May 16, 2022
1a91234
Parse correct inline tags with a bit more care
I-Al-Istannen May 18, 2022
7db0f01
Not quite sure what I am doing tbh
I-Al-Istannen Jun 8, 2022
543220e
Do not expose raw javadoc texts
I-Al-Istannen Jun 8, 2022
cbf368b
Fix parsing of not-quite-block-tags
I-Al-Istannen Jun 8, 2022
d5641cc
Parse inline snippets
I-Al-Istannen Jun 9, 2022
0a4f85e
Add simple snippet file parser
I-Al-Istannen Jun 12, 2022
c641db9
Fix getActiveTagsAtLine
I-Al-Istannen Jun 12, 2022
297b41e
Accept links without reference text
I-Al-Istannen Jun 12, 2022
10b11b1
Correctly resolve relative references to enclosing types
I-Al-Istannen Jun 12, 2022
e5a8bcd
Add some debug code
I-Al-Istannen Jun 12, 2022
9e9a7c0
Parse docRoot as inline tag in block tag parser
I-Al-Istannen Jun 12, 2022
9bd3c99
Treat inline see tag as link tag
I-Al-Istannen Jun 12, 2022
a924fb5
Fix index with quote parsing
I-Al-Istannen Jun 12, 2022
131923d
Fix handling of nested classes without a package
I-Al-Istannen Jun 12, 2022
059c76b
Fix parsing of quoted snippet attributes containing a colon
I-Al-Istannen Jun 12, 2022
dd04577
Fix checkstyle
I-Al-Istannen Jun 13, 2022
0766dd5
Add return type to javadoc visitor
I-Al-Istannen Jun 13, 2022
1f9ea5c
Add some javadoc comments
I-Al-Istannen Jun 13, 2022
e6604a4
Replace regex with code
I-Al-Istannen Jun 13, 2022
916059e
Add licence header
I-Al-Istannen Jun 14, 2022
ad062a8
Add packages for now, though the package name is still wrong
I-Al-Istannen Jun 14, 2022
43cf050
Add some more javadoc
I-Al-Istannen Jun 14, 2022
9fa8a7c
Return a default value in the visitor
I-Al-Istannen Jun 14, 2022
31c7aef
Move to own maven module
I-Al-Istannen Aug 29, 2022
18287d6
Change to reactor build in spoom-pom and externalize versions
I-Al-Istannen Sep 8, 2022
d2e31ba
Remove javadoc package from architecture enforcer test
I-Al-Istannen Sep 8, 2022
b2372bc
Fix reading of inline tags with preceding spaces
I-Al-Istannen Nov 18, 2022
1083010
fix: Properly resolve constructors
I-Al-Istannen Nov 19, 2022
dbd1014
fix: Properly resolve enum constants
I-Al-Istannen Nov 19, 2022
8322373
fix: Reading of block tags with preceding space
I-Al-Istannen Nov 20, 2022
d3b4bbc
fix: Reading of @see labels
I-Al-Istannen Dec 25, 2022
a952498
Delete accidentally committed file
I-Al-Istannen Dec 25, 2022
e3cfebf
Reference the javadoc-parser submodule in spoon element's documentation
I-Al-Istannen Dec 25, 2022
31ffaee
Add some documentation
I-Al-Istannen Dec 25, 2022
7162616
Revert "Reference the javadoc-parser submodule in spoon element's doc…
I-Al-Istannen Jan 3, 2023
5c30d17
Remove link to submodule as it is not yet in master
I-Al-Istannen Jan 3, 2023
2ef9f97
Add javadoc inheritance utilities
I-Al-Istannen Feb 7, 2023
74553f7
Fix link tag label parsing for methods without spaces between parameters
I-Al-Istannen Feb 10, 2023
13a40ba
Fix spoon-version property
I-Al-Istannen Jun 16, 2023
86bb103
Add equals methods
I-Al-Istannen Jun 16, 2023
bd372aa
Parse references in @throws and @exception
I-Al-Istannen Jun 16, 2023
89bb909
Parse reference in @value
I-Al-Istannen Jun 16, 2023
d33adf9
Do not generate empty JavadocText entries
I-Al-Istannen Jun 16, 2023
300ecb8
Start writing tests
I-Al-Istannen Jun 16, 2023
b123612
fix: Parsing of serial
I-Al-Istannen Jun 17, 2023
d3deb1a
fix: Optimistically resolve unknown package/module references
I-Al-Istannen Jun 17, 2023
d0ef36e
Add equals methodto javadoc snippet tags
I-Al-Istannen Jun 17, 2023
cf22274
test: Add more tests
I-Al-Istannen Jun 17, 2023
1a4ac44
Use tabs
I-Al-Istannen Jun 17, 2023
78d2291
Add equals to javadoc snippet markup region
I-Al-Istannen Jun 17, 2023
2fe1f29
fix: Close regions moved to next line correctly
I-Al-Istannen Jun 17, 2023
7627af3
Return Set from SnippetFileParser
I-Al-Istannen Jun 17, 2023
c4e4c41
test: Change tests to use containsExactlyElementsOf to make error mes…
I-Al-Istannen Jun 17, 2023
861b2e2
test: Add tests for snippet parser
I-Al-Istannen Jun 17, 2023
c5c4049
Formatting
I-Al-Istannen Jun 17, 2023
c12a2db
chore: Build spoon-pom in CI
I-Al-Istannen Jun 17, 2023
992a4df
Add jacoco and licences
I-Al-Istannen Jun 17, 2023
9ca6887
Update all tests and reproducible build checks
I-Al-Istannen Jun 17, 2023
dfb13c2
Update doc/spoon_javadoc
I-Al-Istannen Jun 17, 2023
165d50c
Fix package/module guessing crashing on invalid values
I-Al-Istannen Jun 17, 2023
de6f03b
Clarify that block tag contents are an unmodifiable view
I-Al-Istannen Jun 18, 2023
a73bfdf
Reformat with tab-based google-style
I-Al-Istannen Jun 18, 2023
da77be8
Expand qodana workflow
I-Al-Istannen Jun 18, 2023
17ad055
Fix tests after reformat
I-Al-Istannen Jun 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/qodana.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,18 @@ jobs:
- uses: github/codeql-action/upload-sarif@6c089f53dd51dc3fc7e599c3cb5356453a52ca9e # v2
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
code-quality-spoon-javadoc:
runs-on: ubuntu-latest
name: code-quality spoon-javadoc qodana
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
fetch-depth: 0
- name: 'Qodana Scan (spoon-javadoc)'
uses: JetBrains/qodana-action@47c262ae41cc8c13cbc5d349cce1ffb2578ed25c # v2023.1.4
with:
args: --source-directory,./spoon-javadoc/src/main/java , --fail-threshold, 0
post-pr-comment: "false"
- uses: github/codeql-action/upload-sarif@6c089f53dd51dc3fc7e599c3cb5356453a52ca9e # v2
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
14 changes: 7 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ jobs:
run: mv chore/logback.xml src/test/resources/
- name: Build
run: |
mvn -B test-compile
mvn -f spoon-pom -B test-compile
- name: Fetch final dependencies
# this is a hack to download the final test dependencies required to actually run the tests
run: timeout 20 mvn -B test || echo "Done fetching dependencies"
run: timeout 20 mvn -f spoon-pom -B test || echo "Done fetching dependencies"
shell: bash
- name: Test
run:
mvn test
Comment on lines -74 to -75
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to have this multiline?

run:
mvn -f spoon-pom test
- name: print run tests
run: cat testResults.spoon
coverage:
Expand Down Expand Up @@ -100,9 +100,9 @@ jobs:
run: mv chore/logback.xml src/test/resources/
- name: Build
run: |
mvn -B test-compile
mvn -f spoon-pom -B test-compile
- name: Test with coverage
run: mvn -Pcoveralls test jacoco:report coveralls:report -DrepoToken=$GITHUB_TOKEN -DserviceName=github -DpullRequest=$PR_NUMBER --fail-never
run: mvn -f spoon-pom -Pcoveralls test jacoco:report coveralls:report -DrepoToken=$GITHUB_TOKEN -DserviceName=github -DpullRequest=$PR_NUMBER --fail-never
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.number }}
Expand Down Expand Up @@ -168,4 +168,4 @@ jobs:
maven-version: 3.9.0
# we dont enforce that the version must be non snapshot as this is not possible for SNAPSHOT versions in our workflow.
- name: Check maven pom quality
run: mvn org.kordamp.maven:pomchecker-maven-plugin:1.9.0:check-maven-central -D"checker.release=false"
run: mvn -f spoon-pom org.kordamp.maven:pomchecker-maven-plugin:1.9.0:check-maven-central -D"checker.release=false"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this check also run for all submodules now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but there are only two: spoon-javadoc and spoon-core.

13 changes: 10 additions & 3 deletions chore/check-reproducible-builds.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
set -e

build() {
mvn clean package -DskipDepClean -DskipTests -Dmaven.javadoc.skip > /dev/null
mvn -f spoon-pom clean package -DskipDepClean -DskipTests -Dmaven.javadoc.skip > /dev/null
}

compare_files() {
sudo docker run --rm -t -w $(pwd) -v $(pwd):$(pwd):ro \
sudo docker run --rm -t -w "$(pwd)" -v "$(pwd):$(pwd):ro" \
registry.salsa.debian.org/reproducible-builds/diffoscope "$1" "$2"
}

Expand All @@ -19,6 +19,7 @@ build
# Save artifacts
mkdir -p saved_artifacts
cp target/spoon-core-*.jar saved_artifacts
cp spoon-javadoc/target/spoon-javadoc*.jar saved_artifacts

# Build again, will overwrite target jars
build
Expand All @@ -33,7 +34,10 @@ CORE_EXIT="$?"
compare_files target/spoon-core-*dependencies.jar saved_artifacts/spoon-core-*dependencies.jar
DEPS_EXIT="$?"

if [[ "$CORE_EXIT" == 0 && "$DEPS_EXIT" == 0 ]]; then
compare_files spoon-javadoc/target/spoon-javadoc*.jar saved_artifacts/spoon-javadoc*.jar
JAVADOC_EXIT="$?"

if [[ "$CORE_EXIT" == 0 && "$DEPS_EXIT" == 0 && "$JAVADOC_EXIT" == 0 ]]; then
echo -e "\033[1;32mThe jars were reproducible!\033[0m"
exit 0
fi
Expand All @@ -48,6 +52,9 @@ fi
if [[ "$CORE_EXIT" != 0 ]]; then
echo -e " \033[31mspoon-core-VERSION.jar was not reproducible!\033[0m"
fi
if [[ "$JAVADOC_EXIT" != 0 ]]; then
echo -e " \033[31mspoon-javadoc-VERSION.jar was not reproducible!\033[0m"
fi


exit 1
Binary file added doc/images/spoon_javadoc_ansi_print.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
163 changes: 163 additions & 0 deletions doc/spoon_javadoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
title: Javadoc parsing
tags: [javadoc, javadoc-parsing]
keywords: javadoc, javadoc-parsing, comments, spoon
---

The spoon-javadoc submodule provides a parser for javadoc comments, producing a
structured syntax tree representing the comment. Each tag is parsed and
tokenized according to the rules in the javadoc specification. Additionally,
references in e.g. `@link` or `@see` tags are resolved to `CtReference`s,
allowing you to easily analyze them.

A visitor infrastructure is also provided, which eases analyzing comments or
converting them into your own format.

### Installation

On a Unix-like system, the following set of commands should be sufficient for
getting spoon-javadoc up and running from scratch.

```
$ git clone https://github.com/INRIA/spoon.git
$ cd spoon/spoon-pom
$ mvn install
```

### Basic usage

To get started you get the raw javadoc string (including `/**` and `*/`) and
pass it to a newly created `JavadocParser`.
You then call `parse` and get back a list of elements, corresponding to text,
inline tags or block tags.
Using a `JavadocVisitor` you can then visit each of them and drill down a bit.

In the following example, javadoc is parsed and then printed out again -- but
this time with some ANSI color highlighting applied. Note that references are
pretty-printed according to `CtReference#toString()`.

<details>

<summary>Expand me for the code </summary>

```java
void example() {
String javadoc = "/**\n" +
" * Hello world, this is a description.\n" +
" * How are you doing? I am just fine :)\n" +
" * This is an inline link {@link String} and one with a {@link String label}\n" +
" * and a {@link String#CASE_INSENSITIVE_ORDER field} and {@link String#replace(char, char) with a space}.\n" +
" * {@link java.lang.annotation.Target @Target} chained to @Target.\n" +
" * <p>\n" +
" * We can also write <em>very HTML</em> {@code code}.\n" +
" * And an index: {@index \"Hello world\" With a phrase} or {@index without Without a phrase}.\n" +
" * {@snippet lang = java id = \"example me\" foo = 'bar':\n" +
" * public void HelloWorld(){ //@start region = \"foo\"\n" +
" * System.out.println(\"Hello World!\"); // @highlight substring=\"println\"\n" +
" * int a = 10; // @start foo=bar :\n" +
" * int a = 10; // @end\n" +
" * } // @end region=foo\n" +
" *}\n" +
" * <h2><a id=\"resolution\"></a>{@index \"Module Resolution\"}</h2>\n" +
" *\n" +
" * @param args some argument\n" +
" * @author a poor {@literal man}\n" +
" * hello world\n" +
" * @see String#contains(CharSequence) with a label\n" +
" * @see String#replace(char, char)\n" +
" */\n";

List<JavadocElement> elements = new JavadocParser(
// Raw comment string including "/*" and "**/"
// You can get this using CtComment#getRawContent from a spoon element.
javadoc,
// The reference element so resolving of links works correctly.
// Javadoc comments can use "#foo" to refer to fields/methods
// in the current class.
new Launcher().getFactory().Type().OBJECT.getTypeDeclaration()
).parse();

for (JavadocElement element : elements) {
System.out.print(element.accept(new ExampleVisitor()));
}
}

private static class ExampleVisitor implements JavadocVisitor<String> {

@Override
public String defaultValue() {
throw new RuntimeException("Visit method not implemented");
}

@Override
public String visitInlineTag(JavadocInlineTag tag) {
String result = "{@\033[36m" + tag.getTagType().getName() + "\033[0m";
for (JavadocElement element : tag.getElements()) {
result += " " + element.accept(this);
}
result += "}";
return result;
}

@Override
public String visitBlockTag(JavadocBlockTag tag) {
String result = "@\033[36m" + tag.getTagType().getName() + "\033[0m ";
for (JavadocElement element : tag.getElements()) {
result += element.accept(this);
}
result += "\n";
return result;
}

@Override
public String visitText(JavadocText text) {
return text.getText();
}

@Override
public String visitReference(JavadocReference reference) {
return "\033[31m" + reference.getReference() + "\033[0m";
}

@Override
public String visitSnippet(JavadocSnippetTag snippet) {
String result = "{@\033[36m" + snippet.getTagType().getName() + "\033[0m ";
result += snippet.getAttributes()
.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> entry.getKey() + "='" + entry.getValue() + "'")
.collect(Collectors.joining(" "));

result += " : ";
for (JavadocElement element : snippet.getElements()) {
result += element.accept(this);
}

result += "}\n";
return result;
}
}
```

</details>
<br>
This will print a version with a bit more colours:
![ANSI colored javadoc]({{ "/images/spoon_javadoc_ansi_print.png" | prepend: site.baseurl }})

### Snippets
Spoon-javadoc provides the `JavadocSnippetBody` class to help parse javadoc
snippets:
```java
JavadocSnippetBody body = JavadocSnippetBody.fromString(
"class Foo { // @start region=\"foo\"\n" +
" int p0 = 0; // @start region=\"bar\"\n" +
" int p1 = 1;\n" +
" int p2 = 2; // @end\n" +
" int p3 = 3; // @end\n" +
"}\n"
);
body.getLines(); // returns all lines of the original snippet
body.getRegions(); // returns all start/highlight/link regions
body.getActiveRegionsAtLine(0); // returns all regions active in the given line
```
15 changes: 0 additions & 15 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,6 @@
<description>Spoon is a tool for meta-programming, analysis and transformation of Java programs.</description>
<url>http://spoon.gforge.inria.fr/</url>

<licenses>
<license>
<name>CeCILL-C</name>
<comments>French equivalent to LGPL</comments>
<url>https://cecill.info/licences/Licence_CeCILL-C_V1-en.txt</url>
<distribution>repo</distribution>
</license>
<license>
<name>MIT</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
</licenses>

<properties>
<sonar.coverage.exclusions>
**/support/gui/*
Expand Down Expand Up @@ -178,7 +164,6 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the version pinned in a parent or what is the reason behind this change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<executions>
<execution>
<goals>
Expand Down
78 changes: 78 additions & 0 deletions spoon-javadoc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spoon-pom</artifactId>
<groupId>fr.inria.gforge.spoon</groupId>
<version>1.0</version>
<relativePath>../spoon-pom</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>spoon-javadoc</artifactId>
<packaging>jar</packaging>
<version>10.4.0-SNAPSHOT</version>
<name>Spoon Javadoc</name>
<description>A javadoc parser for the java source code analysis tool spoon.</description>

<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check-coverage</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>CLASS</element>
<limits>
<limit implementation="org.jacoco.report.check.Limit">
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.1</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>fr.inria.gforge.spoon</groupId>
<artifactId>spoon-core</artifactId>
<version>${version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
Comment on lines +70 to +75
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is time to simply add this to the parent?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean in the dependency management section?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No the complete test dependency

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-License-Identifier: (MIT OR CECILL-C)
*
* Copyright (C) 2006-2019 INRIA and contributors
*
* Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
*/
package spoon.javadoc.api;

/**
* The category (block or inline) a javadoc tag belongs to. A tag might be able to be used as
* <em>both</em> (e.g. {@code @return}.
*/
public enum JavadocTagCategory {
INLINE,
BLOCK,
MartinWitt marked this conversation as resolved.
Show resolved Hide resolved
}
Loading