mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09208aa49a | ||
|
|
b81ec973a1 | ||
|
|
8fb57b5bab | ||
|
|
f4aaa5852c | ||
|
|
2148b7ede4 | ||
|
|
b2320779e7 | ||
|
|
ef0d65d360 | ||
|
|
d29fde8856 | ||
|
|
524c7efb48 | ||
|
|
a62acfd7b5 | ||
|
|
c40e1d6691 | ||
|
|
57a22bf9de | ||
|
|
ec982fe011 | ||
|
|
1860e24e65 | ||
|
|
cce248c306 | ||
|
|
96aca8ea2b | ||
|
|
70d2bf9016 | ||
|
|
cee3c58d07 | ||
|
|
c141ebe05d | ||
|
|
f5a8c412af | ||
|
|
93440826ed | ||
|
|
80dcae319e | ||
|
|
7371d03db8 | ||
|
|
c6b98e61ff | ||
|
|
ce8f9f60c8 | ||
|
|
cdf27acd9c | ||
|
|
49e5fd1273 | ||
|
|
5085db25c0 | ||
|
|
125d24bc13 | ||
|
|
ea02144bff | ||
|
|
cc2c49edc3 | ||
|
|
8bc878a05c | ||
|
|
b399ef8910 | ||
|
|
7dba641a79 | ||
|
|
da1528129f | ||
|
|
d0bbc5c14b | ||
|
|
da532c79c7 | ||
|
|
04e2900a48 | ||
|
|
f097095398 | ||
|
|
c53a3f64b6 | ||
|
|
cdfcecc204 | ||
|
|
4f4b3fb865 | ||
|
|
cce36d24df | ||
|
|
3bbae43da8 | ||
|
|
3217a6974d | ||
|
|
7b71e4ea3e | ||
|
|
3df6dc957d |
4
.github/workflows/build.yaml
vendored
4
.github/workflows/build.yaml
vendored
@@ -31,11 +31,11 @@ jobs:
|
||||
# additionally enabling all checks defined in this project and any Error
|
||||
# Prone checks available only from other artifact repositories.
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: ${{ matrix.distribution }}
|
||||
|
||||
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -22,11 +22,11 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
distribution: temurin
|
||||
|
||||
8
.github/workflows/deploy-website.yaml
vendored
8
.github/workflows/deploy-website.yaml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@v1.126.0
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
- name: Configure Github Pages
|
||||
uses: actions/configure-pages@v2.1.3
|
||||
uses: actions/configure-pages@f156874f8191504dae5b037505266ed5dda6c382 # v3.0.6
|
||||
- name: Generate documentation
|
||||
run: ./generate-docs.sh
|
||||
- name: Build website with Jekyll
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
# "Refaster rules" terminology on our website and in the code.
|
||||
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
|
||||
- name: Upload website as artifact
|
||||
uses: actions/upload-pages-artifact@v1.0.5
|
||||
uses: actions/upload-pages-artifact@66b63f4a7de003f4f00cc8e9af4b83b8f2abdb96 # v1.0.9
|
||||
with:
|
||||
path: ./website/_site
|
||||
deploy:
|
||||
@@ -48,4 +48,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1.2.3
|
||||
uses: actions/deploy-pages@ee48c7b82e077d7b8ef30b50a719e6a792a50c9a # v2.0.2
|
||||
|
||||
2
.github/workflows/openssf-scorecard.yml
vendored
2
.github/workflows/openssf-scorecard.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
|
||||
6
.github/workflows/pitest-analyze-pr.yml
vendored
6
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -12,12 +12,12 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
distribution: temurin
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Aggregate Pitest reports
|
||||
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
|
||||
- name: Upload Pitest reports as artifact
|
||||
uses: actions/upload-artifact@v3.1.1
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
|
||||
6
.github/workflows/pitest-update-pr.yml
vendored
6
.github/workflows/pitest-update-pr.yml
vendored
@@ -20,17 +20,17 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@v2.24.2
|
||||
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: pitest-reports
|
||||
|
||||
4
.github/workflows/sonarcloud.yml
vendored
4
.github/workflows/sonarcloud.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
distribution: temurin
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"helpers:pinGitHubActionDigests"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
|
||||
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
|
||||
import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
|
||||
/** A {@link BugChecker} that flags likely missing Refaster annotations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "The Refaster rule contains a method without any Refaster annotations",
|
||||
link = BUG_PATTERNS_BASE_URL + "MissingRefasterAnnotation",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class MissingRefasterAnnotation extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final MultiMatcher<Tree, AnnotationTree> REFASTER_ANNOTATION =
|
||||
annotations(
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType("com.google.errorprone.refaster.annotation.Placeholder"),
|
||||
isType("com.google.errorprone.refaster.annotation.BeforeTemplate"),
|
||||
isType("com.google.errorprone.refaster.annotation.AfterTemplate")));
|
||||
|
||||
/** Instantiates a new {@link MissingRefasterAnnotation} instance. */
|
||||
public MissingRefasterAnnotation() {}
|
||||
|
||||
@Override
|
||||
public Description matchClass(ClassTree tree, VisitorState state) {
|
||||
long methodTypes =
|
||||
tree.getMembers().stream()
|
||||
.filter(member -> member.getKind() == Tree.Kind.METHOD)
|
||||
.map(MethodTree.class::cast)
|
||||
.filter(method -> !ASTHelpers.isGeneratedConstructor(method))
|
||||
.map(method -> REFASTER_ANNOTATION.matches(method, state))
|
||||
.distinct()
|
||||
.count();
|
||||
|
||||
return methodTypes < 2 ? Description.NO_MATCH : buildDescription(tree).build();
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,8 @@ final class CollectionRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
|
||||
@SuppressWarnings(
|
||||
"NonApiType" /* Matching against `List` would unnecessarily constrain the rule. */)
|
||||
static final class NewArrayListFromCollection<T> {
|
||||
@BeforeTemplate
|
||||
ArrayList<T> before(Collection<T> collection) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Comparator;
|
||||
@@ -19,6 +20,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Optional}s. */
|
||||
@OnlineDocumentation
|
||||
@@ -118,7 +120,7 @@ final class OptionalRules {
|
||||
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
|
||||
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Maybe our `Refaster` checker should test `compilesWithFix`?
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
abstract static class TernaryOperatorOptionalPositiveFiltering<T> {
|
||||
@Placeholder
|
||||
abstract boolean test(T value);
|
||||
@@ -138,7 +140,7 @@ final class OptionalRules {
|
||||
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
|
||||
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Maybe our `Refaster` checker should test `compilesWithFix`?
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
abstract static class TernaryOperatorOptionalNegativeFiltering<T> {
|
||||
@Placeholder
|
||||
abstract boolean test(T value);
|
||||
@@ -161,6 +163,7 @@ final class OptionalRules {
|
||||
*/
|
||||
static final class MapOptionalToBoolean<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("OptionalOrElseGet" /* Rule is confused by `Refaster#anyOf` usage. */)
|
||||
boolean before(Optional<T> optional, Function<? super T, Boolean> predicate) {
|
||||
return optional.map(predicate).orElse(Refaster.anyOf(false, Boolean.FALSE));
|
||||
}
|
||||
@@ -224,6 +227,28 @@ final class OptionalRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the
|
||||
* fallback value is not the result of a trivial computation.
|
||||
*/
|
||||
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
// XXX: Once `MethodReferenceUsage` is "production ready", replace
|
||||
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and
|
||||
// reimplement the matcher accordingly).
|
||||
static final class OptionalOrElseGet<T> {
|
||||
@BeforeTemplate
|
||||
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) {
|
||||
return optional.orElse(value);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Optional<T> optional, T value) {
|
||||
return optional.orElseGet(() -> value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten a stream of {@link Optional}s using {@link Optional#stream()}, rather than using one of
|
||||
* the more verbose alternatives.
|
||||
@@ -325,6 +350,9 @@ final class OptionalRules {
|
||||
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
|
||||
// XXX: Note that rewriting the first and third variant will change the code's behavior if
|
||||
// `optional2` has side-effects.
|
||||
// XXX: Note that rewriting the first and third variant will introduce a compilation error if
|
||||
// `optional2` is not effectively final. Review whether a `@Matcher` can be used to avoid
|
||||
// this.
|
||||
return Refaster.anyOf(
|
||||
optional1.map(Optional::of).orElse(optional2),
|
||||
optional1.map(Optional::of).orElseGet(() -> optional2),
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -54,6 +53,6 @@ final class AssertJIsNullTest {
|
||||
" assertThat(\"foo\").isNull();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TEXT_MATCH);
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.base.Predicates.containsPattern;
|
||||
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MissingRefasterAnnotationTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(MissingRefasterAnnotation.class, getClass())
|
||||
.expectErrorMessage(
|
||||
"X",
|
||||
containsPattern("The Refaster rule contains a method without any Refaster annotations"))
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.annotation.AfterTemplate;",
|
||||
"import com.google.errorprone.refaster.annotation.AlsoNegation;",
|
||||
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
|
||||
"import java.util.Map;",
|
||||
"",
|
||||
"class A {",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" static final class MethodLacksBeforeTemplateAnnotation {",
|
||||
" @BeforeTemplate",
|
||||
" boolean before1(String string) {",
|
||||
" return string.equals(\"\");",
|
||||
" }",
|
||||
"",
|
||||
" // @BeforeTemplate is missing",
|
||||
" boolean before2(String string) {",
|
||||
" return string.length() == 0;",
|
||||
" }",
|
||||
"",
|
||||
" @AfterTemplate",
|
||||
" @AlsoNegation",
|
||||
" boolean after(String string) {",
|
||||
" return string.isEmpty();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" static final class MethodLacksAfterTemplateAnnotation {",
|
||||
" @BeforeTemplate",
|
||||
" boolean before(String string) {",
|
||||
" return string.equals(\"\");",
|
||||
" }",
|
||||
"",
|
||||
" // @AfterTemplate is missing",
|
||||
" boolean after(String string) {",
|
||||
" return string.isEmpty();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" abstract class MethodLacksPlaceholderAnnotation<K, V> {",
|
||||
" // @Placeholder is missing",
|
||||
" abstract V function(K key);",
|
||||
"",
|
||||
" @BeforeTemplate",
|
||||
" void before(Map<K, V> map, K key) {",
|
||||
" if (!map.containsKey(key)) {",
|
||||
" map.put(key, function(key));",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @AfterTemplate",
|
||||
" void after(Map<K, V> map, K key) {",
|
||||
" map.computeIfAbsent(key, k -> function(k));",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" static final class ValidRefasterRule {",
|
||||
" @BeforeTemplate",
|
||||
" void unusedPureFunctionCall(Object o) {",
|
||||
" o.toString();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" static final class NotARefasterRule {",
|
||||
" @Override",
|
||||
" public String toString() {",
|
||||
" return \"This is not a Refaster rule\";",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -145,6 +144,6 @@ final class NonEmptyMonoTest {
|
||||
" Mono.just(2).hasElement();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TEXT_MATCH);
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,4 +119,11 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional<String> testOptionalMap() {
|
||||
return Optional.of(1).stream().map(String::valueOf).findAny();
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElse(String.valueOf(true)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,4 +112,11 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional<String> testOptionalMap() {
|
||||
return Optional.of(1).map(String::valueOf);
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElseGet(() -> String.valueOf(true)));
|
||||
}
|
||||
}
|
||||
|
||||
65
pom.xml
65
pom.xml
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Picnic :: Error Prone Support</name>
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:PicnicSupermarket/error-prone-support.git</developerConnection>
|
||||
<tag>v0.11.1</tag>
|
||||
<tag>v0.12.0</tag>
|
||||
<url>https://github.com/PicnicSupermarket/error-prone-support</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
@@ -141,7 +141,7 @@
|
||||
<groupId.error-prone>com.google.errorprone</groupId.error-prone>
|
||||
<!-- The build timestamp is derived from the most recent commit
|
||||
timestamp in support of reproducible builds. -->
|
||||
<project.build.outputTimestamp>2023-05-16T15:37:41Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>2023-06-21T19:08:33Z</project.build.outputTimestamp>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Glob pattern identifying Refaster rule definition files. These
|
||||
Java classes don't contain "regular" code, and thus require special
|
||||
@@ -197,11 +197,11 @@
|
||||
<!-- Dependency and plugin versions that are referenced in more than
|
||||
one place. We use these to keep dependencies in sync. Version numbers
|
||||
that need to be referenced only once should *not* be listed here. -->
|
||||
<version.auto-service>1.0.1</version.auto-service>
|
||||
<version.auto-service>1.1.1</version.auto-service>
|
||||
<version.auto-value>1.10.1</version.auto-value>
|
||||
<version.error-prone>${version.error-prone-orig}</version.error-prone>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.19.1</version.error-prone-orig>
|
||||
<version.error-prone-orig>2.20.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.18</version.error-prone-slf4j>
|
||||
<version.guava-beta-checker>1.0</version.guava-beta-checker>
|
||||
<version.jdk>11</version.jdk>
|
||||
@@ -209,8 +209,8 @@
|
||||
<version.mockito>5.3.1</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.10.10</version.nullaway>
|
||||
<version.pitest-git>1.0.10</version.pitest-git>
|
||||
<version.surefire>3.1.0</version.surefire>
|
||||
<version.pitest-git>1.0.11</version.pitest-git>
|
||||
<version.surefire>3.1.2</version.surefire>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -268,7 +268,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson</groupId>
|
||||
<artifactId>jackson-bom</artifactId>
|
||||
<version>2.15.0</version>
|
||||
<version>2.15.2</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -307,14 +307,14 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>31.1-jre</version>
|
||||
<version>32.0.1-jre</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.truth</groupId>
|
||||
<artifactId>truth</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<version>1.1.4</version>
|
||||
</dependency>
|
||||
<!-- Specified as a workaround for
|
||||
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
|
||||
@@ -326,7 +326,7 @@
|
||||
<dependency>
|
||||
<groupId>com.newrelic.agent.java</groupId>
|
||||
<artifactId>newrelic-api</artifactId>
|
||||
<version>8.2.0</version>
|
||||
<version>8.3.0</version>
|
||||
</dependency>
|
||||
<!-- Specified as a workaround for
|
||||
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
|
||||
@@ -338,7 +338,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2022.0.7</version>
|
||||
<version>2022.0.8</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -350,12 +350,12 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.6.10</version>
|
||||
<version>1.6.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.9</version>
|
||||
<version>2.2.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
@@ -387,7 +387,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.4</version>
|
||||
<version>1.14.5</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -412,7 +412,7 @@
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.34.0</version>
|
||||
<version>3.35.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -458,12 +458,12 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>2.7.11</version>
|
||||
<version>2.7.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>7.7.1</version>
|
||||
<version>7.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
@@ -570,7 +570,7 @@
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<version>6.0.0</version>
|
||||
<configuration>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<runOnlyOnce>true</runOnlyOnce>
|
||||
@@ -589,7 +589,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<checkstyleRules>
|
||||
<!-- We only enable rules that are not enforced by
|
||||
@@ -839,7 +839,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.11.0</version>
|
||||
<version>10.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -940,7 +940,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<!-- XXX: Drop `ignoreAllNonTestScoped` once
|
||||
https://issues.apache.org/jira/browse/MNG-6058 is
|
||||
@@ -972,7 +972,7 @@
|
||||
<banDuplicateClasses>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<groupId>io.github.eisop</groupId>
|
||||
<artifactId>dataflow-errorprone</artifactId>
|
||||
<!-- This package is contained in
|
||||
Checker Framework's `checker-qual` and
|
||||
@@ -1051,7 +1051,7 @@
|
||||
<dependency>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>extra-enforcer-rules</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<version>1.7.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -1141,7 +1141,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<preparationProfiles>release</preparationProfiles>
|
||||
@@ -1168,7 +1168,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<version>3.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-source-jar</id>
|
||||
@@ -1202,7 +1202,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<version>2.1.0</version>
|
||||
<configuration>
|
||||
<includedLicenses>
|
||||
<!-- The SPDX IDs of licenses of third-party
|
||||
@@ -1305,7 +1305,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.15.0</version>
|
||||
<version>2.16.0</version>
|
||||
<configuration>
|
||||
<updateBuildOutputTimestampPolicy>never</updateBuildOutputTimestampPolicy>
|
||||
</configuration>
|
||||
@@ -1356,7 +1356,7 @@
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.13.1</version>
|
||||
<version>1.14.1</version>
|
||||
<configuration>
|
||||
<excludedClasses>
|
||||
<!-- AutoValue generated classes. -->
|
||||
@@ -1385,7 +1385,7 @@
|
||||
<dependency>
|
||||
<groupId>com.groupcdg.arcmutate</groupId>
|
||||
<artifactId>base</artifactId>
|
||||
<version>1.0.4</version>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.groupcdg.pitest</groupId>
|
||||
@@ -1395,7 +1395,7 @@
|
||||
<dependency>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-junit5-plugin</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<version>1.2.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -1720,6 +1720,9 @@
|
||||
-Xep:Java7ApiChecker:OFF
|
||||
<!-- We don't target JDK 8. -->
|
||||
-Xep:Java8ApiChecker:OFF
|
||||
<!-- XXX: Triggers an IOOBE. See
|
||||
https://github.com/google/error-prone/pull/3976. -->
|
||||
-Xep:MemberName:OFF
|
||||
<!-- We don't target Android. -->
|
||||
-Xep:StaticOrDefaultInterfaceMethod:OFF
|
||||
<!-- We generally discourage `var` use. -->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-runner</artifactId>
|
||||
@@ -45,6 +45,7 @@
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import tech.picnic.errorprone.refaster.ErrorProneFork;
|
||||
|
||||
final class RefasterTest {
|
||||
private final CompilationTestHelper compilationHelper =
|
||||
@@ -80,74 +79,66 @@ final class RefasterTest {
|
||||
SeverityLevel defaultSeverity = BugCheckerInfo.create(Refaster.class).defaultSeverity();
|
||||
|
||||
/* { arguments, expectedSeverities } */
|
||||
return Stream.concat(
|
||||
Stream.of(
|
||||
arguments(
|
||||
ImmutableList.of(), ImmutableList.of(defaultSeverity, WARNING, ERROR, SUGGESTION)),
|
||||
arguments(ImmutableList.of("-Xep:Refaster:OFF"), ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:DEFAULT"),
|
||||
ImmutableList.of(defaultSeverity, WARNING, ERROR, SUGGESTION)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:WARN"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:ERROR"),
|
||||
ImmutableList.of(ERROR, ERROR, ERROR, ERROR)),
|
||||
arguments(
|
||||
ImmutableList.of("-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(defaultSeverity, WARNING, WARNING, SUGGESTION)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:OFF", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:DEFAULT", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(defaultSeverity, WARNING, WARNING, SUGGESTION)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:WARN", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:ERROR", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING))),
|
||||
ErrorProneFork.isErrorProneForkAvailable()
|
||||
? Stream.of(
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:OFF", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:DEFAULT", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, ERROR, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:WARN", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:ERROR", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(ERROR, ERROR, ERROR, ERROR)),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:OFF",
|
||||
"-XepAllErrorsAsWarnings",
|
||||
"-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:DEFAULT",
|
||||
"-XepAllErrorsAsWarnings",
|
||||
"-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:WARN",
|
||||
"-XepAllErrorsAsWarnings",
|
||||
"-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:ERROR",
|
||||
"-XepAllErrorsAsWarnings",
|
||||
"-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)))
|
||||
: Stream.empty());
|
||||
return Stream.of(
|
||||
arguments(
|
||||
ImmutableList.of(), ImmutableList.of(defaultSeverity, WARNING, ERROR, SUGGESTION)),
|
||||
arguments(ImmutableList.of("-Xep:Refaster:OFF"), ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:DEFAULT"),
|
||||
ImmutableList.of(defaultSeverity, WARNING, ERROR, SUGGESTION)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:WARN"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:ERROR"), ImmutableList.of(ERROR, ERROR, ERROR, ERROR)),
|
||||
arguments(
|
||||
ImmutableList.of("-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(defaultSeverity, WARNING, WARNING, SUGGESTION)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:OFF", "-XepAllErrorsAsWarnings"), ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:DEFAULT", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(defaultSeverity, WARNING, WARNING, SUGGESTION)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:WARN", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:ERROR", "-XepAllErrorsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, ERROR, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:OFF", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:DEFAULT", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, ERROR, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:WARN", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of("-Xep:Refaster:ERROR", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(ERROR, ERROR, ERROR, ERROR)),
|
||||
arguments(
|
||||
ImmutableList.of("-XepAllErrorsAsWarnings", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:OFF", "-XepAllErrorsAsWarnings", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of()),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:DEFAULT", "-XepAllErrorsAsWarnings", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:WARN", "-XepAllErrorsAsWarnings", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)),
|
||||
arguments(
|
||||
ImmutableList.of(
|
||||
"-Xep:Refaster:ERROR", "-XepAllErrorsAsWarnings", "-XepAllSuggestionsAsWarnings"),
|
||||
ImmutableList.of(WARNING, WARNING, WARNING, WARNING)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-support</artifactId>
|
||||
|
||||
@@ -148,8 +148,7 @@ public abstract class AnnotatedCompositeCodeTransformer implements CodeTransform
|
||||
|
||||
private static SeverityLevel overrideSeverity(SeverityLevel severity, Context context) {
|
||||
ErrorProneOptions options = context.get(ErrorProneOptions.class);
|
||||
SeverityLevel minSeverity =
|
||||
ErrorProneFork.isSuggestionsAsWarningsEnabled(options) ? WARNING : SUGGESTION;
|
||||
SeverityLevel minSeverity = options.isSuggestionsAsWarnings() ? WARNING : SUGGESTION;
|
||||
SeverityLevel maxSeverity = options.isDropErrorsToWarnings() ? WARNING : ERROR;
|
||||
|
||||
return Comparators.max(Comparators.min(severity, minSeverity), maxSeverity);
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package tech.picnic.errorprone.refaster;
|
||||
|
||||
import com.google.errorprone.ErrorProneOptions;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Utility class that enables the runtime to determine whether Picnic's fork of Error Prone is on
|
||||
* the classpath.
|
||||
*
|
||||
* @see <a href="https://github.com/PicnicSupermarket/error-prone">Picnic's Error Prone fork</a>
|
||||
*/
|
||||
public final class ErrorProneFork {
|
||||
private static final Optional<Method> ERROR_PRONE_OPTIONS_IS_SUGGESTIONS_AS_WARNINGS_METHOD =
|
||||
Arrays.stream(ErrorProneOptions.class.getDeclaredMethods())
|
||||
.filter(m -> Modifier.isPublic(m.getModifiers()))
|
||||
.filter(m -> "isSuggestionsAsWarnings".equals(m.getName()))
|
||||
.findFirst();
|
||||
|
||||
private ErrorProneFork() {}
|
||||
|
||||
/**
|
||||
* Tells whether Picnic's fork of Error Prone is available.
|
||||
*
|
||||
* @return {@code true} iff classpath introspection indicates the presence of Error Prone
|
||||
* modifications that are assumed to be present only in Picnic's fork.
|
||||
*/
|
||||
public static boolean isErrorProneForkAvailable() {
|
||||
return ERROR_PRONE_OPTIONS_IS_SUGGESTIONS_AS_WARNINGS_METHOD.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the custom {@code -XepAllSuggestionsAsWarnings} flag is set.
|
||||
*
|
||||
* @param options The currently active Error Prone options.
|
||||
* @return {@code true} iff {@link #isErrorProneForkAvailable() the Error Prone fork is available}
|
||||
* and the aforementioned flag is set.
|
||||
* @see <a href="https://github.com/google/error-prone/pull/3301">google/error-prone#3301</a>
|
||||
*/
|
||||
public static boolean isSuggestionsAsWarningsEnabled(ErrorProneOptions options) {
|
||||
return ERROR_PRONE_OPTIONS_IS_SUGGESTIONS_AS_WARNINGS_METHOD
|
||||
.filter(m -> Boolean.TRUE.equals(invoke(m, options)))
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
private static Object invoke(Method method, Object obj, Object... args) {
|
||||
try {
|
||||
return method.invoke(obj, args);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException(String.format("Failed to invoke method '%s'", method), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ArrayAccessTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.ParenthesizedTree;
|
||||
import com.sun.source.tree.TypeCastTree;
|
||||
import com.sun.source.tree.UnaryTree;
|
||||
|
||||
/** A matcher of expressions that likely require little to no computation. */
|
||||
public final class IsLikelyTrivialComputation implements Matcher<ExpressionTree> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link IsLikelyTrivialComputation} instance. */
|
||||
public IsLikelyTrivialComputation() {}
|
||||
|
||||
@Override
|
||||
public boolean matches(ExpressionTree expressionTree, VisitorState state) {
|
||||
if (expressionTree instanceof MethodInvocationTree) {
|
||||
// XXX: Method invocations are generally *not* trivial computations, but we make an exception
|
||||
// for nullary method invocations on the result of a trivial computation. This exception
|
||||
// allows this `Matcher` to by the `OptionalOrElseGet` Refaster rule, such that it does not
|
||||
// suggest the introduction of lambda expressions that are better expressed as method
|
||||
// references. Once the `MethodReferenceUsage` bug checker is production-ready, this exception
|
||||
// should be removed. (But at that point, instead defining a `RequiresComputation` matcher may
|
||||
// be more appropriate.)
|
||||
MethodInvocationTree methodInvocation = (MethodInvocationTree) expressionTree;
|
||||
if (methodInvocation.getArguments().isEmpty()
|
||||
&& matches(methodInvocation.getMethodSelect())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return matches(expressionTree);
|
||||
}
|
||||
|
||||
// XXX: Some `BinaryTree`s may represent what could be considered "trivial computations".
|
||||
// Depending on feedback such trees may be matched in the future.
|
||||
private static boolean matches(ExpressionTree expressionTree) {
|
||||
if (expressionTree instanceof ArrayAccessTree) {
|
||||
return matches(((ArrayAccessTree) expressionTree).getExpression())
|
||||
&& matches(((ArrayAccessTree) expressionTree).getIndex());
|
||||
}
|
||||
|
||||
if (expressionTree instanceof LiteralTree) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expressionTree instanceof LambdaExpressionTree) {
|
||||
/*
|
||||
* Lambda expressions encapsulate computations, but their definition does not involve
|
||||
* significant computation.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expressionTree instanceof IdentifierTree) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expressionTree instanceof MemberReferenceTree) {
|
||||
return matches(((MemberReferenceTree) expressionTree).getQualifierExpression());
|
||||
}
|
||||
|
||||
if (expressionTree instanceof MemberSelectTree) {
|
||||
return matches(((MemberSelectTree) expressionTree).getExpression());
|
||||
}
|
||||
|
||||
if (expressionTree instanceof ParenthesizedTree) {
|
||||
return matches(((ParenthesizedTree) expressionTree).getExpression());
|
||||
}
|
||||
|
||||
if (expressionTree instanceof TypeCastTree) {
|
||||
return matches(((TypeCastTree) expressionTree).getExpression());
|
||||
}
|
||||
|
||||
if (expressionTree instanceof UnaryTree) {
|
||||
// XXX: Arguably side-effectful options such as pre- and post-increment and -decrement are not
|
||||
// trivial.
|
||||
return matches(((UnaryTree) expressionTree).getExpression());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package tech.picnic.errorprone.refaster;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.ErrorProneOptions;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ErrorProneForkTest {
|
||||
@Test
|
||||
void isErrorProneForkAvailable() {
|
||||
assertThat(ErrorProneFork.isErrorProneForkAvailable())
|
||||
.isEqualTo(Boolean.TRUE.toString().equals(System.getProperty("error-prone-fork-in-use")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isSuggestionsAsWarningsEnabledWithoutFlag() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains: Suggestions as warnings enabled: false",
|
||||
"class A {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isSuggestionsAsWarningsEnabledWithFlag() {
|
||||
assumeTrue(
|
||||
ErrorProneFork.isErrorProneForkAvailable(),
|
||||
"Picnic's Error Prone fork is not on the classpath");
|
||||
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.setArgs("-XepAllSuggestionsAsWarnings")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains: Suggestions as warnings enabled: true",
|
||||
"class A {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that reports the result of {@link
|
||||
* ErrorProneFork#isSuggestionsAsWarningsEnabled(ErrorProneOptions)}.
|
||||
*/
|
||||
@BugPattern(summary = "Flags classes with a custom error message", severity = ERROR)
|
||||
public static final class TestChecker extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Description matchClass(ClassTree tree, VisitorState state) {
|
||||
return buildDescription(tree)
|
||||
.setMessage(
|
||||
String.format(
|
||||
"Suggestions as warnings enabled: %s",
|
||||
ErrorProneFork.isSuggestionsAsWarningsEnabled(state.errorProneOptions())))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,11 @@ import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.ImportTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.TypeCastTree;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -31,18 +34,27 @@ abstract class AbstractMatcherTestChecker extends BugChecker implements Compilat
|
||||
|
||||
@Override
|
||||
public Description matchCompilationUnit(CompilationUnitTree compilationUnit, VisitorState state) {
|
||||
new TreeScanner<@Nullable Void, @Nullable Void>() {
|
||||
new TreeScanner<@Nullable Void, TreePath>() {
|
||||
@Override
|
||||
public @Nullable Void scan(Tree tree, @Nullable Void unused) {
|
||||
if (tree instanceof ExpressionTree && delegate.matches((ExpressionTree) tree, state)) {
|
||||
state.reportMatch(describeMatch(tree));
|
||||
public @Nullable Void scan(@Nullable Tree tree, TreePath treePath) {
|
||||
if (tree == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.scan(tree, unused);
|
||||
TreePath path = new TreePath(treePath, tree);
|
||||
if (tree instanceof ExpressionTree) {
|
||||
ExpressionTree expressionTree = (ExpressionTree) tree;
|
||||
if (!isMethodSelect(expressionTree, path)
|
||||
&& delegate.matches(expressionTree, state.withPath(path))) {
|
||||
state.reportMatch(describeMatch(tree));
|
||||
}
|
||||
}
|
||||
|
||||
return super.scan(tree, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitImport(ImportTree node, @Nullable Void unused) {
|
||||
public @Nullable Void visitImport(ImportTree tree, TreePath path) {
|
||||
/*
|
||||
* We're not interested in matching import statements. While components of these
|
||||
* can be `ExpressionTree`s, they will never be matched by Refaster.
|
||||
@@ -51,15 +63,42 @@ abstract class AbstractMatcherTestChecker extends BugChecker implements Compilat
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitMethod(MethodTree node, @Nullable Void unused) {
|
||||
public @Nullable Void visitMethod(MethodTree tree, TreePath path) {
|
||||
/*
|
||||
* We're not interested in matching e.g. parameter and return type declarations. While these
|
||||
* can be `ExpressionTree`s, they will never be matched by Refaster.
|
||||
*/
|
||||
return scan(node.getBody(), unused);
|
||||
return scan(tree.getBody(), new TreePath(path, tree));
|
||||
}
|
||||
}.scan(compilationUnit, null);
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitTypeCast(TypeCastTree tree, TreePath path) {
|
||||
/*
|
||||
* We're not interested in matching the parenthesized type subtree that is part of a type
|
||||
* cast expression. While such trees can be `ExpressionTree`s, they will never be matched by
|
||||
* Refaster.
|
||||
*/
|
||||
return scan(tree.getExpression(), new TreePath(path, tree));
|
||||
}
|
||||
}.scan(compilationUnit, state.getPath());
|
||||
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given {@link ExpressionTree} is the {@link
|
||||
* MethodInvocationTree#getMethodSelect() method select} portion of a method invocation.
|
||||
*
|
||||
* <p>Such {@link ExpressionTree}s will never be matched by Refaster.
|
||||
*/
|
||||
private static boolean isMethodSelect(ExpressionTree tree, TreePath path) {
|
||||
TreePath parentPath = path.getParentPath();
|
||||
if (parentPath == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Tree parentTree = parentPath.getLeaf();
|
||||
return parentTree instanceof MethodInvocationTree
|
||||
&& ((MethodInvocationTree) parentTree).getMethodSelect().equals(tree);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.sun.source.tree.ReturnTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class IsLikelyTrivialComputationTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.function.Predicate;",
|
||||
"",
|
||||
"class A {",
|
||||
" String negative1() {",
|
||||
" return String.valueOf(1);",
|
||||
" }",
|
||||
"",
|
||||
" String negative2() {",
|
||||
" return toString().toString();",
|
||||
" }",
|
||||
"",
|
||||
" String negative3() {",
|
||||
" return \"foo\" + toString();",
|
||||
" }",
|
||||
"",
|
||||
" byte negative4() {",
|
||||
" return \"foo\".getBytes()[0];",
|
||||
" }",
|
||||
"",
|
||||
" int negative5() {",
|
||||
" int[] arr = new int[0];",
|
||||
" return arr[hashCode()];",
|
||||
" }",
|
||||
"",
|
||||
" int negative6() {",
|
||||
" return 1 * 2;",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> negative7() {",
|
||||
" return toString()::equals;",
|
||||
" }",
|
||||
"",
|
||||
" String negative8() {",
|
||||
" return (toString());",
|
||||
" }",
|
||||
"",
|
||||
" Object negative9() {",
|
||||
" return (Object) toString();",
|
||||
" }",
|
||||
"",
|
||||
" int negative10() {",
|
||||
" return -hashCode();",
|
||||
" }",
|
||||
"",
|
||||
" String positive1() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return toString();",
|
||||
" }",
|
||||
"",
|
||||
" String positive2() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return this.toString();",
|
||||
" }",
|
||||
"",
|
||||
" int positive3() {",
|
||||
" int[] arr = new int[0];",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return arr[0];",
|
||||
" }",
|
||||
"",
|
||||
" String positive4() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return null;",
|
||||
" }",
|
||||
"",
|
||||
" boolean positive5() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return false;",
|
||||
" }",
|
||||
"",
|
||||
" int positive6() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return 0;",
|
||||
" }",
|
||||
"",
|
||||
" String positive7() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return \"foo\" + \"bar\";",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive8() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return v -> \"foo\".equals(v);",
|
||||
" }",
|
||||
"",
|
||||
" A positive9() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return this;",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive10() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return \"foo\"::equals;",
|
||||
" }",
|
||||
"",
|
||||
" A positive11() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return (this);",
|
||||
" }",
|
||||
"",
|
||||
" Object positive12() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return (Object) this;",
|
||||
" }",
|
||||
"",
|
||||
" boolean positive13() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return !false;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that simply delegates to {@link IsLikelyTrivialComputation}. */
|
||||
@BugPattern(
|
||||
summary = "Flags return statement expressions matched by `IsLikelyTrivialComputation`",
|
||||
severity = ERROR)
|
||||
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// XXX: This is a false positive reported by Checkstyle. See
|
||||
// https://github.com/checkstyle/checkstyle/issues/10161#issuecomment-1242732120.
|
||||
@SuppressWarnings("RedundantModifier")
|
||||
public MatcherTestChecker() {
|
||||
super(
|
||||
(expressionTree, state) ->
|
||||
state.getPath().getParentPath().getLeaf() instanceof ReturnTree
|
||||
&& new IsLikelyTrivialComputation().matches(expressionTree, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Executes Pitest to determine the code base' mutation test coverage. The set
|
||||
# of tests executed can optionally be restricted by name. The results are found
|
||||
# in each Maven module's `target/pit-reports` directory.
|
||||
# Executes Pitest to determine the code's mutation test coverage. The set of
|
||||
# tests executed can optionally be restricted by name. The results are found in
|
||||
# each Maven module's `target/pit-reports` directory.
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
@@ -11,7 +11,7 @@ if [ "${#}" -gt 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
targetTests=${1:-*}
|
||||
targetTests="${1:-*}"
|
||||
|
||||
mvn clean test pitest:mutationCoverage \
|
||||
-DargLine.xmx=2048m \
|
||||
|
||||
Reference in New Issue
Block a user