Compare commits

..

9 Commits

Author SHA1 Message Date
Stephan Schroevers
d5f24c966b THIS 2025-02-23 15:14:40 +01:00
Stephan Schroevers
001243f31a OTHER 2025-02-23 15:14:32 +01:00
Stephan Schroevers
8909323e37 WIP: Part of this PR 2025-02-23 15:05:41 +01:00
Stephan Schroevers
4803b7c051 WIP: TO SEPARATE PR 2025-02-23 15:05:25 +01:00
Stephan Schroevers
9882a5047d X 2025-02-22 21:44:59 +01:00
Stephan Schroevers
1c78a0d0c2 MERGE SEPARATE 2025-02-22 21:44:51 +01:00
Stephan Schroevers
789a2be195 Suggestions 2025-02-22 21:29:52 +01:00
Stephan Schroevers
70aa735a77 TO SEPARATE PR 2025-02-22 21:29:37 +01:00
mohamedsamehsalah
2c66daa6f3 Introduce EmptyReactivePublisher bug checker 2025-02-22 14:07:48 +01:00
52 changed files with 1249 additions and 517 deletions

View File

@@ -26,7 +26,7 @@ jobs:
continue-on-error: ${{ matrix.experimental }}
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block

View File

@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block
@@ -40,13 +40,13 @@ jobs:
java-distribution: temurin
maven-version: 3.9.9
- name: Initialize CodeQL
uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
languages: ${{ matrix.language }}
- name: Perform minimal build
if: matrix.language == 'java'
run: mvn -T1C clean package -DskipTests -Dverification.skip
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
category: /language:${{ matrix.language }}

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block
@@ -43,7 +43,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
- uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
with:
working-directory: ./website
bundler-cache: true
@@ -75,7 +75,7 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block
@@ -42,12 +42,12 @@ jobs:
with:
persist-credentials: false
- name: Run OpenSSF Scorecard analysis
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
publish_results: ${{ github.ref == 'refs/heads/master' }}
- name: Update GitHub's code scanning dashboard
uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
with:
sarif_file: results.sarif

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block
@@ -38,7 +38,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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: pitest-reports
path: ./target/pit-reports-ci

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block

View File

@@ -22,7 +22,7 @@ jobs:
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block
@@ -55,7 +55,7 @@ jobs:
run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: "integration-test-${{ matrix.integration-test }}"
path: "${{ runner.temp }}/artifacts"

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
with:
disable-sudo: true
egress-policy: block

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>documentation-support</artifactId>

View File

@@ -2,7 +2,6 @@ package tech.picnic.errorprone.documentation;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -168,10 +167,7 @@ public final class BugPatternTestExtractor implements Extractor<BugPatternTestCa
* is safe, because this code is guarded by an earlier call to `#getClassUnderTest(..)`,
* which ensures that `tree` is part of a longer method invocation chain.
*/
MethodInvocationTree inputTree =
(MethodInvocationTree)
requireNonNull(
ASTHelpers.getReceiver(tree), "Instance method invocation must have receiver");
MethodInvocationTree inputTree = (MethodInvocationTree) ASTHelpers.getReceiver(tree);
String path = ASTHelpers.constValue(inputTree.getArguments().get(0), String.class);
Optional<String> inputCode = getSourceCode(inputTree);

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
@@ -62,16 +62,6 @@
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<!-- XXX: JSR-305 (meta-)annotation usage by some dependencies triggers
NullAway to attempt to load said annotations. As such some modules
require these annotations to be on the classpath. Periodically review
whether we can drop this dependeny declaration. See
https://github.com/uber/NullAway/issues/1171. -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>

View File

@@ -11,7 +11,6 @@ import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.returnStatement;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
@@ -80,10 +79,7 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
return Description.NO_MATCH;
}
Symbol variableSymbol =
requireNonNull(
ASTHelpers.getSymbol(((ReturnTree) finalStatement).getExpression()),
"Missing symbol for returned variable");
Symbol variableSymbol = ASTHelpers.getSymbol(((ReturnTree) finalStatement).getExpression());
StatementTree precedingStatement = statements.get(statements.size() - 2);
return tryMatchAssignment(variableSymbol, precedingStatement)

View File

@@ -0,0 +1,247 @@
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.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.nullLiteral;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreTypePredicates.isSubTypeOf;
import static tech.picnic.errorprone.utils.MoreTypes.generic;
import static tech.picnic.errorprone.utils.MoreTypes.type;
import static tech.picnic.errorprone.utils.MoreTypes.unbound;
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.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import java.util.function.Consumer;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@link Publisher} operations that are known to be vacuous, given
* that they are applied to a {@link Mono} or {@link Flux} that does not emit {@code onNext}
* signals.
*/
// XXX: Also match (effectively) final variables that reference provably-empty publishers.
// XXX: Also handle `#subscribe` invocations with a non-null value consumer.
// XXX: Suggest a fix, or document why we don't (e.g. because this this requires inference of the
// type of the `Mono` or `Flux`).
@AutoService(BugChecker.class)
@BugPattern(
summary = "Avoid vacuous operations on empty `Publisher`s",
link = BUG_PATTERNS_BASE_URL + "EmptyPublisher",
linkType = CUSTOM,
severity = WARNING,
tags = SIMPLIFICATION)
public final class EmptyPublisher extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Supplier<Type> VOID = type(Void.class.getCanonicalName());
private static final Supplier<Type> MONO =
Suppliers.typeFromString("reactor.core.publisher.Mono");
private static final Supplier<Type> FLUX =
Suppliers.typeFromString("reactor.core.publisher.Flux");
private static final TypePredicate CONSUMER =
isSubTypeOf(generic(type(Consumer.class.getCanonicalName()), unbound()));
// XXX: There are many operators that do not change the number of `onNext` signals, such as
// `onErrorComplete()` or `publishOn(Scheduler)`. Cover those cases as well.
private static final Matcher<ExpressionTree> EMPTY_FLUX =
anyOf(
staticMethod().onDescendantOf(FLUX).namedAnyOf("empty", "never"),
typePredicateMatcher(isSubTypeOf(generic(FLUX, VOID))));
private static final Matcher<ExpressionTree> EMPTY_MONO =
anyOf(
staticMethod().onDescendantOf(MONO).namedAnyOf("empty", "never"),
typePredicateMatcher(isSubTypeOf(generic(MONO, VOID))));
// XXX: Include `reduce` and `scan` in this list. Only the 1-arg variants are a no-op.
// XXX: Include the non-duration `take` variants in this list.
// XXX: Not a no-op, and may be dropped if types match:
// - all
// - any
// - count
// - reduce with two arguments (can be `startWith(x)`?)
// - reduceWith
// - scan with two arguments (can be `startWith(x)`?)
// - scanWith
// - last, single (+ others; see Refaster rules).
// XXX: The `collect*` (and possibly some of the `buffer*` and `window*`) operations below do
// change what's
// emitted. Handle differently.
// XXX: Should this list include `groupJoin`, `join`, `windowWhen`, `withLatestFrom`,
// `zipWith`...?
// XXX: The `onBackpressure*` and some `take` operators do influence how much is requested
// upstream, and may thus not be true no-ops; evaluate whether they should really be part of this
// list.
// XXX: What about `publish`?
// XXX: What about `toIterable()` and `toStream()`?
private static final Matcher<ExpressionTree> VACUOUS_EMPTY_FLUX_OPERATORS =
instanceMethod()
.onDescendantOf(FLUX)
.namedAnyOf(
"buffer",
"bufferTimeout",
"bufferUntil",
"bufferUntilChanged",
"bufferWhile",
"collect",
"collectList",
"collectMap",
"collectMultimap",
"collectSortedList",
"concatMap",
"concatMapDelayError",
"concatMapIterable",
"delayElements",
"delaySequence",
"delayUntil",
"distinct",
"distinctUntilChanged",
"doOnNext",
"elapsed",
"expand",
"expandDeep",
"filter",
"filterWhen",
"flatMap",
"flatMapDelayError",
"flatMapIterable",
"flatMapSequential",
"flatMapSequentialDelayError",
"groupBy",
"handle",
"ignoreElements",
"index",
"limitRate",
"map",
"mapNotNull",
"next",
"ofType",
"onBackpressureBuffer",
"onBackpressureDrop",
"onBackpressureError",
"onBackpressureLatest",
"parallel",
"sample",
"sampleFirst",
"sampleTimeout",
"singleOrEmpty",
"skip",
"skipLast",
"skipUntil",
"skipWhile",
"sort",
"switchMap",
"take",
"takeLast",
"takeUntil",
"takeWhile",
"timed",
"timestamp",
"window",
"windowTimeout",
"windowUntil",
"windowUntilChanged",
"windowWhile",
"zipWithIterable");
private static final Matcher<ExpressionTree> VACUOUS_EMPTY_MONO_OPERATORS =
instanceMethod()
.onDescendantOf(MONO)
.namedAnyOf(
"delayElement",
"delayUntil",
"doOnNext",
"expand",
"expandDeep",
"filter",
"filterWhen",
"flatMap",
"flatMapIterable",
"flatMapMany",
"handle",
"ignoreElement",
"map",
"mapNotNull",
"ofType",
"timestamp",
"zipWhen",
"zipWith");
private static final Matcher<ExpressionTree> SUBSCRIBE =
instanceMethod()
.onDescendantOf(Suppliers.typeFromString("org.reactivestreams.Publisher"))
.named("subscribe");
/** Instantiates a new {@link EmptyPublisher} instance. */
public EmptyPublisher() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
// XXX: Factor our the matcher result for reuse below.
if (receiver == null
|| (!EMPTY_FLUX.matches(receiver, state) && !EMPTY_MONO.matches(receiver, state))) {
return Description.NO_MATCH;
}
if (!tree.getArguments().isEmpty() && SUBSCRIBE.matches(tree, state)) {
/*
* The first argument to `#subscribe` overloads is either an `onNext` signal consumer or a
* `Subscriber`. In the former case, for known-empty publishers, this argument should be
* `null`.
*/
ExpressionTree firstArgument = tree.getArguments().get(0);
if (!nullLiteral().matches(firstArgument, state)
&& CONSUMER.apply(ASTHelpers.getSymbol(tree).getParameters().get(0).asType(), state)) {
return buildDescription(firstArgument)
.setMessage("Passing an on next signal `Consumer` on empty `Publisher`s is a no-op")
.build();
}
}
if (EMPTY_FLUX.matches(receiver, state) && VACUOUS_EMPTY_FLUX_OPERATORS.matches(tree, state)) {
// XXX: Do the same as for `Mono` below, and update the tests.
// XXX: Here and below: don't call it a no-op if the return type is changed. Test error
// messages!
return buildDescription(tree)
.setMessage(
String.format(
"Operator `%s` on an empty `Flux`s is a no-op",
ASTHelpers.getSymbol(tree).getSimpleName()))
.build();
}
if (EMPTY_MONO.matches(receiver, state) && VACUOUS_EMPTY_MONO_OPERATORS.matches(tree, state)) {
Description.Builder description = buildDescription(tree);
if (state.getTypes().isSubtype(ASTHelpers.getType(receiver), ASTHelpers.getType(tree))) {
description.addFix(SuggestedFix.replace(tree, SourceCode.treeToString(receiver, state)));
}
return description
.setMessage(
String.format(
"Operator `%s` on an empty `Mono`s is a no-op",
ASTHelpers.getSymbol(tree).getSimpleName()))
.build();
}
return Description.NO_MATCH;
}
}

View File

@@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -34,8 +33,6 @@ import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -181,45 +178,30 @@ public final class ExplicitArgumentEnumeration extends BugChecker
state.getTypes())
.collect(toImmutableList());
return hasLikelySuitableVarargsOverload(method, overloads, state)
/*
* If all overloads have a single parameter, and at least one of them is a varargs method, then
* we assume that unwrapping the iterable argument will cause a suitable overload to be invoked.
* (Note that there may be multiple varargs overloads, either with different parameter types, or
* due to method overriding; this check does not attempt to determine which exact method or
* overload will be invoked as a result of the suggested simplification.)
*
* Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
* type to change from `RowN` to (e.g.) `Row2`.
*/
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
// XXX: Ideally we do check that one of the overloads accepts the unwrapped arguments.
// XXX: Ideally we validate that eligible overloads have compatible return types.
boolean hasLikelySuitableVarargsOverload =
overloads.stream().allMatch(m -> m.params().size() == 1)
&& overloads.stream().anyMatch(MethodSymbol::isVarArgs);
return hasLikelySuitableVarargsOverload
? Optional.of(SourceCode.unwrapMethodInvocation(argument, state))
: Optional.empty();
}
/**
* Tells whether it is likely that, if the argument to the given method is unwrapped, a suitable
* varargs overload will be invoked instead.
*
* <p>If all overloads have a single parameter, and at least one of them is a suitably-typed
* varargs method, then we assume that unwrapping the iterable argument will cause a suitable
* overload to be invoked. (Note that there may be multiple varargs overloads due to method
* overriding; this check does not attempt to determine which exact method or overload will be
* invoked as a result of the suggested simplification.)
*
* <p>Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
* type to change from `RowN` to (e.g.) `Row2`.
*/
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
// XXX: Ideally we validate that eligible overloads have compatible return types.
private static boolean hasLikelySuitableVarargsOverload(
MethodSymbol method, ImmutableList<MethodSymbol> overloads, VisitorState state) {
Types types = state.getTypes();
// XXX: This logic is fragile, as it assumes that the method parameter's type is of the form
// `X<T>`, where `T` is the type of the explicitly enumerated values passed to the expression to
// be unwrapped. This should generally hold, given the types returned by the
// `EXPLICIT_ITERABLE_CREATOR` expressions: `Iterable<T>`, `List<T>`, `Set<T>`, etc.
Type parameterType =
Iterables.getOnlyElement(
Iterables.getOnlyElement(method.getParameters()).type.getTypeArguments());
return overloads.stream().allMatch(m -> m.params().size() == 1)
&& overloads.stream()
.filter(MethodSymbol::isVarArgs)
.map(m -> types.elemtype(Iterables.getOnlyElement(m.getParameters()).type))
.anyMatch(varArgsType -> types.containsType(parameterType, varArgsType));
}
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
MethodInvocationTree tree, MethodInvocationTree argument, VisitorState state) {
return ALTERNATIVE_METHODS.rowMap().entrySet().stream()

View File

@@ -17,7 +17,6 @@ import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.methodHasParameters;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
@@ -130,10 +129,7 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
return Description.NO_MATCH;
}
Type parameterType =
requireNonNull(
ASTHelpers.getType(Iterables.getOnlyElement(tree.getParameters())),
"Missing type for method parameter");
Type parameterType = ASTHelpers.getType(Iterables.getOnlyElement(tree.getParameters()));
return findMethodSourceAnnotation(tree, state)
.flatMap(
@@ -177,9 +173,7 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
private static Optional<MethodTree> findMatchingSibling(
MethodTree tree, Predicate<? super MethodTree> predicate, VisitorState state) {
return requireNonNull(state.findEnclosing(ClassTree.class), "No class enclosing method")
.getMembers()
.stream()
return state.findEnclosing(ClassTree.class).getMembers().stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.filter(not(tree::equals))

View File

@@ -5,7 +5,6 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
@@ -87,9 +86,7 @@ public final class NonEmptyMono extends BugChecker implements MethodInvocationTr
return Description.NO_MATCH;
}
ExpressionTree receiver =
requireNonNull(
ASTHelpers.getReceiver(tree), "Instance method invocation must have receiver");
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
if (!NON_EMPTY_MONO.matches(receiver, state)) {
return Description.NO_MATCH;
}

View File

@@ -204,11 +204,6 @@ final class AssertJEnumerableRules {
return enumAssert.hasSize(iterable.length);
}
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, CharSequence iterable) {
return enumAssert.hasSize(iterable.length());
}
@AfterTemplate
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
return enumAssert.hasSameSizeAs(iterable);

View File

@@ -4,7 +4,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import java.io.File;
@@ -12,7 +11,6 @@ import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
@@ -143,35 +141,4 @@ final class FileRules {
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
}
}
/**
* Invoke {@link File#mkdirs()} before {@link Files#exists(Path, LinkOption...)} to avoid
* concurrency issues.
*/
static final class PathToFileMkDirsFilesExists {
@BeforeTemplate
boolean before(Path path) {
return Files.exists(path) || path.toFile().mkdirs();
}
@AfterTemplate
@AlsoNegation
boolean after(Path path) {
return path.toFile().mkdirs() || Files.exists(path);
}
}
/** Invoke {@link File#mkdirs()} before {@link File#exists()} to avoid concurrency issues. */
static final class FileMkDirsFileExists {
@BeforeTemplate
boolean before(File file) {
return file.exists() || file.mkdirs();
}
@AfterTemplate
@AlsoNegation
boolean after(File file) {
return file.mkdirs() || file.exists();
}
}
}

View File

@@ -32,6 +32,7 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
@@ -59,6 +60,8 @@ import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
/** Refaster rules related to Reactor expressions and statements. */
// For `@Matches(IsEmpty) {mono,flux}`, can `#takeUntilOther` and `#skipUntilOther` be replaced with
// `#or` or some other merge operator?
@OnlineDocumentation
final class ReactorRules {
private ReactorRules() {}
@@ -374,12 +377,228 @@ final class ReactorRules {
mono.then(Mono.just(object)));
}
@BeforeTemplate
Mono<T> before2(@Matches(IsEmpty.class) Mono<T> mono, T object) {
return mono.defaultIfEmpty(object);
}
@AfterTemplate
Mono<S> after(Mono<T> mono, S object) {
return mono.thenReturn(object);
}
}
/**
* Avoid vacuous invocations of {@link Mono#hasElement()} when the receiver is known to be empty;
* explicitly communicate the element emitted downstream instead.
*/
// XXX: If we introduce an `IsNotEmpty` matcher, we can introduce a similar `MonoThenReturnTrue`
// rule.
static final class MonoThenReturnFalse<T> {
@BeforeTemplate
Mono<Boolean> before(@Matches(IsEmpty.class) Mono<T> mono) {
return mono.hasElement();
}
@AfterTemplate
Mono<Boolean> after(Mono<T> mono) {
return mono.thenReturn(false);
}
}
/**
* Avoid invocations of {@link Flux#elementAt(int, Object)}, {@link Flux#last(Object)} and {@link
* Flux#single(Object)} when the receiver is known to be empty; explicitly communicate the element
* emitted downstream instead.
*/
static final class FluxThenMonoJust<T> {
@BeforeTemplate
Mono<T> before(@Matches(IsEmpty.class) Flux<T> flux, T value, int index) {
return Refaster.anyOf(flux.elementAt(index, value), flux.last(value), flux.single(value));
}
@AfterTemplate
Mono<T> after(Flux<T> flux, T value) {
return flux.then(Mono.just(value));
}
}
/**
* Avoid invocations of {@link Flux#defaultIfEmpty(Object)} when the receiver is known to be
* empty; explicitly communicate the element emitted downstream instead.
*/
static final class FluxThenManyMonoJust<T> {
@BeforeTemplate
Flux<T> before(@Matches(IsEmpty.class) Flux<T> flux, T value) {
return flux.defaultIfEmpty(value);
}
@AfterTemplate
Flux<T> after(Flux<T> flux, T value) {
// XXX: One could argue it'd even be clearer here to do `.then(...).flux()`, to indicate that
// this is really a `Mono` in disguise.
return flux.thenMany(Mono.just(value));
}
}
/**
* Avoid vacuous invocations of {@link Flux#any(Predicate)}, {@code Flux#hasElements} and {@link
* Flux#hasElement(Object)} when the receiver is known to be empty; explicitly communicate the
* element emitted downstream instead.
*/
static final class FluxThenMonoJustFalse<T> {
@BeforeTemplate
Mono<Boolean> before(
@Matches(IsEmpty.class) Flux<T> flux, Predicate<? super T> predicate, T element) {
return Refaster.anyOf(flux.any(predicate), flux.hasElements(), flux.hasElement(element));
}
@AfterTemplate
Mono<Boolean> after(Flux<T> flux) {
return flux.then(Mono.just(false));
}
}
/**
* Avoid vacuous invocations of {@link Flux#all(Predicate)} when the receiver is known to be
* empty; explicitly communicate the element emitted downstream instead.
*/
static final class FluxThenMonoJustTrue<T> {
@BeforeTemplate
Mono<Boolean> before(@Matches(IsEmpty.class) Flux<T> flux, Predicate<? super T> predicate) {
return flux.all(predicate);
}
@AfterTemplate
Mono<Boolean> after(Flux<T> flux) {
return flux.then(Mono.just(true));
}
}
/**
* Avoid vacuous invocations of {@link Flux#count()} when the receiver is known to be empty;
* explicitly communicate the element emitted downstream instead.
*/
static final class FluxThenMonoJust0<T> {
@BeforeTemplate
Mono<Long> before(@Matches(IsEmpty.class) Flux<T> flux) {
return flux.count();
}
@AfterTemplate
Mono<Integer> after(Flux<T> flux) {
return flux.then(Mono.just(0));
}
}
/**
* Avoid vacuous invocations of {@link Flux#buffer} when the receiver is known to be empty;
* explicitly communicate the element emitted downstream instead.
*/
// XXX: The replacement expression introduces an immutable list, where the original expression
// emits a mutable `ArrayList`. This fact isn't documented, though.
// XXX: Likely this rule will be replaced. Similarly handle `collectMap`, `collectMultimap`,
// `collectSortedList`
static final class FluxThenMonoJustImmutableListOf<T> {
@BeforeTemplate
Mono<List<T>> before(@Matches(IsEmpty.class) Flux<T> flux) {
return flux.collectList();
}
@AfterTemplate
Mono<List<T>> after(Flux<T> flux) {
return flux.then(Mono.just(ImmutableList.of()));
}
}
/**
* Avoid vacuous invocations of {@link Flux#buffer} when the receiver is known to be empty;
* explicitly communicate the element emitted downstream instead.
*/
// XXX: The replacement expression introduces an immutable list, where the original expressions
// emit a mutable `ArrayList`. This fact isn't documented, though.
static final class FluxThenMonoJustImmutableListOfFlux<T> {
@BeforeTemplate
Flux<List<T>> before(@Matches(IsEmpty.class) Flux<T> flux, int maxSize, int skip) {
return Refaster.anyOf(flux.buffer(), flux.buffer(maxSize), flux.buffer(maxSize, skip));
}
@AfterTemplate
Flux<List<T>> after(Flux<T> flux) {
return flux.then(Mono.<List<T>>just(ImmutableList.of())).flux();
}
}
/**
* Avoid vacuous invocations of {@link Flux#elementAt(int)} when the receiver is known to be
* empty; explicitly communicate that an {@link IndexOutOfBoundsException} will be emitted
* instead.
*/
static final class FluxThenMonoErrorNewIndexOutOfBoundsException<T> {
@BeforeTemplate
Mono<T> before(@Matches(IsEmpty.class) Flux<T> flux, int index) {
return flux.elementAt(index);
}
@AfterTemplate
Mono<T> after(Flux<T> flux, int index) {
return flux.then(Mono.error(() -> new IndexOutOfBoundsException(index)));
}
}
/**
* Avoid vacuous invocations of {@link Flux#last()} and {@link Flux#single()} when the receiver is
* known to be empty; explicitly communicate that an {@link NoSuchElementException} will be
* emitted instead.
*/
static final class FluxThenMonoErrorNoSuchElementExceptionNew<T> {
@BeforeTemplate
Mono<T> before(@Matches(IsEmpty.class) Flux<T> flux) {
return Refaster.anyOf(flux.last(), flux.single());
}
@AfterTemplate
Mono<T> after(Flux<T> flux) {
return flux.then(Mono.error(NoSuchElementException::new));
}
}
/**
* Avoid vacuous invocations of {@link Flux#buffer} when the receiver is known to be empty;
* explicitly communicate the element emitted downstream instead.
*/
static final class FluxThenMonoFromSupplierFlux<T, C extends Collection<? super T>> {
@BeforeTemplate
Flux<C> before(
@Matches(IsEmpty.class) Flux<T> flux, Supplier<C> bufferSupplier, int maxSize, int skip) {
return Refaster.anyOf(
flux.buffer(maxSize, bufferSupplier), flux.buffer(maxSize, skip, bufferSupplier));
}
@AfterTemplate
Flux<C> after(Flux<T> flux, Supplier<C> bufferSupplier) {
return flux.then(Mono.fromSupplier(bufferSupplier)).flux();
}
}
/**
* Avoid vacuous invocations of {@link Mono#singleOptional()} when the receiver is known to be
* empty; explicitly communicate the element emitted downstream instead.
*/
// XXX: If we introduce an `IsNotEmpty` matcher, we can introduce a similar
// `MonoThenReturnOptionalOf` rule.
static final class MonoThenReturnOptionalEmpty<T> {
@BeforeTemplate
Mono<Optional<T>> before(@Matches(IsEmpty.class) Mono<T> mono) {
return mono.singleOptional();
}
@AfterTemplate
Mono<Optional<T>> after(Mono<T> mono) {
return mono.thenReturn(Optional.empty());
}
}
/**
* Prefer {@link Flux#take(long)} over {@link Flux#take(long, boolean)} where relevant.
*
@@ -489,16 +708,9 @@ final class ReactorRules {
return Flux.range(value, 1);
}
// XXX: Consider generalizing part of this template using an Error Prone check that covers any
// sequence of explicitly enumerated values passed to an iteration order-preserving collection
// factory method.
@BeforeTemplate
Flux<T> before(T value) {
return Refaster.anyOf(
Mono.just(value).flux(),
Mono.just(value).repeat().take(1),
Flux.fromIterable(ImmutableList.of(value)),
Flux.fromIterable(ImmutableSet.of(value)));
return Mono.just(value).repeat().take(1);
}
@AfterTemplate
@@ -515,15 +727,9 @@ final class ReactorRules {
mono.switchIfEmpty(Mono.empty()), mono.flux().next(), mono.flux().singleOrEmpty());
}
// XXX: Consider filing a SonarCloud issue for the S2637 false positive.
@BeforeTemplate
@SuppressWarnings({
"java:S2637" /* False positive: result is never `null`. */,
"java:S4968" /* Result may be `Mono<Void>`. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
Mono<? extends @Nullable Void> before2(Mono<@Nullable Void> mono) {
return Refaster.anyOf(mono.ignoreElement(), mono.then());
Mono<@Nullable Void> before2(Mono<@Nullable Void> mono) {
return mono.then();
}
// XXX: Replace this rule with an extension of the `IdentityConversion` rule, supporting
@@ -951,44 +1157,31 @@ final class ReactorRules {
/** Prefer direct invocation of {@link Mono#then()}} over more contrived alternatives. */
static final class MonoThen<T> {
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Mono<T> mono) {
return Refaster.anyOf(
mono.ignoreElement().then(),
mono.flux().then(),
Mono.when(mono),
Mono.whenDelayError(mono));
Mono<@Nullable Void> before(Mono<T> mono) {
return Refaster.anyOf(mono.ignoreElement().then(), mono.flux().then());
}
@AfterTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Mono<T> mono) {
Mono<@Nullable Void> after(Mono<T> mono) {
return mono.then();
}
}
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
// XXX: Check whether there's a nice non-Void alternative to `emptyFlux#next()`.
static final class FluxThen<T> {
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Flux<T> flux) {
Mono<@Nullable Void> before(Flux<T> flux) {
return flux.ignoreElements().then();
}
// XXX: Consider filing a SonarCloud issue for the S2637 false positive.
@BeforeTemplate
@SuppressWarnings({
"java:S2637" /* False positive: result is never `null`. */,
"java:S4968" /* Result may be `Mono<Void>`. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
Mono<? extends @Nullable Void> before2(Flux<@Nullable Void> flux) {
Mono<@Nullable Void> before2(Flux<@Nullable Void> flux) {
return flux.ignoreElements();
}
@AfterTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Flux<T> flux) {
Mono<@Nullable Void> after(Flux<T> flux) {
return flux.then();
}
}
@@ -996,14 +1189,12 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */
static final class MonoThenEmpty<T> {
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Mono<T> mono, Publisher<@Nullable Void> publisher) {
Mono<@Nullable Void> before(Mono<T> mono, Publisher<@Nullable Void> publisher) {
return mono.ignoreElement().thenEmpty(publisher);
}
@AfterTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Mono<T> mono, Publisher<@Nullable Void> publisher) {
Mono<@Nullable Void> after(Mono<T> mono, Publisher<@Nullable Void> publisher) {
return mono.thenEmpty(publisher);
}
}
@@ -1011,14 +1202,12 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThenEmpty<T> {
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Flux<T> flux, Publisher<@Nullable Void> publisher) {
Mono<@Nullable Void> before(Flux<T> flux, Publisher<@Nullable Void> publisher) {
return flux.ignoreElements().thenEmpty(publisher);
}
@AfterTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Flux<T> flux, Publisher<@Nullable Void> publisher) {
Mono<@Nullable Void> after(Flux<T> flux, Publisher<@Nullable Void> publisher) {
return flux.thenEmpty(publisher);
}
}
@@ -1060,6 +1249,11 @@ final class ReactorRules {
return flux.ignoreElements().thenMany(publisher);
}
@BeforeTemplate
Flux<T> before2(@Matches(IsEmpty.class) Flux<T> flux, Publisher<? extends T> publisher) {
return Refaster.anyOf(flux.concatWith(publisher), flux.switchIfEmpty(publisher));
}
@AfterTemplate
Flux<S> after(Flux<T> flux, Publisher<S> publisher) {
return flux.thenMany(publisher);
@@ -1074,8 +1268,12 @@ final class ReactorRules {
}
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before2(Mono<T> mono1, Mono<@Nullable Void> mono2) {
Mono<T> before2(@Matches(IsEmpty.class) Mono<T> mono1, Mono<? extends T> mono2) {
return mono1.switchIfEmpty(mono2);
}
@BeforeTemplate
Mono<@Nullable Void> before3(Mono<T> mono1, Mono<@Nullable Void> mono2) {
return mono1.thenEmpty(mono2);
}
@@ -1093,8 +1291,7 @@ final class ReactorRules {
}
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before2(Flux<T> flux, Mono<@Nullable Void> mono) {
Mono<@Nullable Void> before2(Flux<T> flux, Mono<@Nullable Void> mono) {
return flux.thenEmpty(mono);
}
@@ -1111,12 +1308,10 @@ final class ReactorRules {
// rule. Consider introducing an Error Prone check for this.
static final class MonoSingleOptional<T> {
@BeforeTemplate
Mono<Optional<T>> before(Mono<T> mono, Optional<T> optional, Mono<Optional<T>> alternate) {
Mono<Optional<T>> before(Mono<T> mono) {
return Refaster.anyOf(
mono.flux().collect(toOptional()),
mono.map(Optional::of),
mono.singleOptional().defaultIfEmpty(optional),
mono.singleOptional().switchIfEmpty(alternate),
mono.map(Optional::of).defaultIfEmpty(Optional.empty()),
mono.transform(Mono::singleOptional));
}
@@ -1127,26 +1322,40 @@ final class ReactorRules {
}
}
/** Prefer {@link Mono#cast(Class)} over {@link Mono#map(Function)} with a cast. */
/** Prefer {@link Mono#cast(Class)} over more contrived alternatives. */
static final class MonoCast<T, S> {
@BeforeTemplate
Mono<S> before(Mono<T> mono) {
return mono.map(Refaster.<S>clazz()::cast);
}
// XXX: In cases where this template matches, often the `cast` operation can be avoided by
// passing an explicit type argument to the preceding reactive operator.
@BeforeTemplate
Mono<S> before2(@Matches(IsEmpty.class) Mono<T> mono) {
return mono.ofType(Refaster.<S>clazz());
}
@AfterTemplate
Mono<S> after(Mono<T> mono) {
return mono.cast(Refaster.<S>clazz());
}
}
/** Prefer {@link Flux#cast(Class)} over {@link Flux#map(Function)} with a cast. */
/** Prefer {@link Flux#cast(Class)} over more contrived alternatives. */
static final class FluxCast<T, S> {
@BeforeTemplate
Flux<S> before(Flux<T> flux) {
return flux.map(Refaster.<S>clazz()::cast);
}
// XXX: In cases where this template matches, often the `cast` operation can be avoided by
// passing an explicit type argument to the preceding reactive operator.
@BeforeTemplate
Flux<S> before2(@Matches(IsEmpty.class) Flux<T> flux) {
return flux.ofType(Refaster.<S>clazz());
}
@AfterTemplate
Flux<S> after(Flux<T> flux) {
return flux.cast(Refaster.<S>clazz());

View File

@@ -23,16 +23,14 @@ final class RxJava2AdapterRules {
/** Use the fluent API style when using {@link RxJava2Adapter#completableToMono}. */
static final class CompletableToMono {
@BeforeTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Completable completable) {
Mono<@Nullable Void> before(Completable completable) {
return Refaster.anyOf(
RxJava2Adapter.completableToMono(completable),
completable.to(RxJava2Adapter::completableToMono));
}
@AfterTemplate
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Completable completable) {
Mono<@Nullable Void> after(Completable completable) {
return completable.as(RxJava2Adapter::completableToMono);
}
}

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -66,18 +65,16 @@ final class SuggestedFixRules {
}
}
/**
* Prefer {@link SuggestedFix#swap(Tree, Tree, VisitorState)} over more contrived alternatives.
*/
/** Prefer {@link SuggestedFix#swap(Tree, Tree)} over more contrived alternatives. */
static final class SuggestedFixSwap {
@BeforeTemplate
SuggestedFix before(Tree tree1, Tree tree2, VisitorState state) {
return SuggestedFix.builder().swap(tree1, tree2, state).build();
SuggestedFix before(Tree tree1, Tree tree2) {
return SuggestedFix.builder().swap(tree1, tree2).build();
}
@AfterTemplate
SuggestedFix after(Tree tree1, Tree tree2, VisitorState state) {
return SuggestedFix.swap(tree1, tree2, state);
SuggestedFix after(Tree tree1, Tree tree2) {
return SuggestedFix.swap(tree1, tree2);
}
}

View File

@@ -0,0 +1,119 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class EmptyPublisherTest {
// XXX: Reorder test cases.
// XXX: Update numbering.
@Test
void identification() {
CompilationTestHelper.newInstance(EmptyPublisher.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableSet;",
"import org.reactivestreams.Subscriber;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Mono.just(0).subscribe(i -> {});",
" Mono.just(1).doOnNext(i -> {});",
" Mono.just(2).filter(i -> true);",
" Mono.just(3).flatMap(Mono::just);",
" Mono.just(4).flatMapMany(Flux::just);",
" Mono.just(5).flatMapIterable(ImmutableSet::of);",
" Mono.just(6).handle((i, j) -> {});",
" Mono.just(7).map(i -> i);",
"",
" // BUG: Diagnostic contains: doOnNext",
" Mono.empty().doOnNext(i -> {});",
" // BUG: Diagnostic contains: filter",
" Mono.empty().filter(i -> true);",
" // BUG: Diagnostic contains: flatMap",
" Mono.empty().flatMap(Mono::just);",
" // BUG: Diagnostic contains: flatMapMany",
" Mono.empty().flatMapMany(Flux::just);",
" // BUG: Diagnostic contains: flatMapIterable",
" Mono.empty().flatMapIterable(ImmutableSet::of);",
" // BUG: Diagnostic contains: handle",
" Mono.empty().handle((i, j) -> {});",
" // BUG: Diagnostic contains: map",
" Mono.empty().map(i -> i);",
"",
" // BUG: Diagnostic contains: doOnNext",
" Flux.empty().doOnNext(i -> {});",
" // BUG: Diagnostic contains: filter",
" Flux.empty().filter(i -> true);",
" // BUG: Diagnostic contains: concatMap",
" Flux.empty().concatMap(Mono::just);",
" // BUG: Diagnostic contains: flatMap",
" Flux.empty().flatMap(Mono::just);",
" // BUG: Diagnostic contains: flatMapSequential",
" Flux.empty().flatMapSequential(Flux::just);",
" // BUG: Diagnostic contains: flatMapIterable",
" Flux.empty().flatMapIterable(ImmutableSet::of);",
" // BUG: Diagnostic contains: handle",
" Flux.empty().handle((i, j) -> {});",
" // BUG: Diagnostic contains: map",
" Flux.empty().map(i -> i);",
"",
" // BUG: Diagnostic contains: doOnNext",
" Mono.just(8).then().doOnNext(i -> {});",
" // BUG: Diagnostic contains: filter",
" Mono.just(9).then().filter(i -> true);",
" // BUG: Diagnostic contains: flatMap",
" Mono.just(10).then().flatMap(Mono::just);",
" // BUG: Diagnostic contains: flatMapMany",
" Mono.just(11).then().flatMapMany(Flux::just);",
" // BUG: Diagnostic contains: flatMapIterable",
" Mono.just(12).then().flatMapIterable(ImmutableSet::of);",
" // BUG: Diagnostic contains: handle",
" Mono.just(13).then().handle((i, j) -> {});",
" // BUG: Diagnostic contains: map",
" Mono.just(14).then().map(i -> i);",
"",
" Mono.just(15).then().subscribe();",
" Mono.just(16).then().subscribe((Subscriber<Object>) null);",
" Mono.just(17).then().subscribe(null, t -> {});",
"",
" // BUG: Diagnostic contains:",
" Mono.just(17).then().subscribe(i -> {});",
" // BUG: Diagnostic contains:",
" Mono.just(18).then().subscribe(i -> {}, t -> {});",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(EmptyPublisher.class, getClass())
.addInputLines(
"A.java",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Mono.empty().map(i -> 1);",
" Mono.empty().doOnNext(i -> {});",
" Mono.empty().doOnNext(i -> {}).onErrorComplete();",
" }",
"}")
.addOutputLines(
"A.java",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Mono.empty().map(i -> 1);",
" Mono.empty();",
" Mono.empty().onErrorComplete();",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -16,8 +16,6 @@ final class ExplicitArgumentEnumerationTest {
"import com.google.common.collect.ImmutableList;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import io.micrometer.core.instrument.Counter;",
"import io.micrometer.core.instrument.Tag;",
"import org.jooq.impl.DSL;",
"import reactor.core.publisher.Flux;",
"import reactor.test.StepVerifier;",
@@ -34,8 +32,6 @@ final class ExplicitArgumentEnumerationTest {
"",
" DSL.row(ImmutableList.of(1, 2));",
"",
" Counter.builder(\"foo\").tags(ImmutableList.of(Tag.of(\"bar\", \"baz\")));",
"",
" // BUG: Diagnostic contains:",
" unaryMethod(ImmutableList.of(1, 2));",
" unaryMethodWithLessVisibleOverload(ImmutableList.of(1, 2));",

View File

@@ -67,11 +67,10 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
assertThat(ImmutableSet.of(4)).size().isBetween(5, 6));
}
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertHasSameSizeAs() {
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {
return ImmutableSet.of(
assertThat("foo").hasSize(Iterables.size(ImmutableSet.of(1))),
assertThat("bar").hasSize(ImmutableSet.of(2).size()),
assertThat("baz").hasSize(new Integer[0].length),
assertThat("qux").hasSize("quux".length()));
assertThat(ImmutableSet.of(1)).hasSize(Iterables.size(ImmutableSet.of(2))),
assertThat(ImmutableSet.of(3)).hasSize(ImmutableSet.of(4).size()),
assertThat(ImmutableSet.of(5)).hasSize(new Integer[0].length));
}
}

View File

@@ -66,11 +66,10 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
assertThat(ImmutableSet.of(4)).hasSizeBetween(5, 6));
}
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertHasSameSizeAs() {
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {
return ImmutableSet.of(
assertThat("foo").hasSameSizeAs(ImmutableSet.of(1)),
assertThat("bar").hasSameSizeAs(ImmutableSet.of(2)),
assertThat("baz").hasSameSizeAs(new Integer[0]),
assertThat("qux").hasSameSizeAs("quux"));
assertThat(ImmutableSet.of(1)).hasSameSizeAs(ImmutableSet.of(2)),
assertThat(ImmutableSet.of(3)).hasSameSizeAs(ImmutableSet.of(4)),
assertThat(ImmutableSet.of(5)).hasSameSizeAs(new Integer[0]));
}
}

View File

@@ -39,16 +39,4 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return File.createTempFile("foo", "bar", new File("baz"));
}
ImmutableSet<Boolean> testPathToFileMkDirsFilesExists() {
return ImmutableSet.of(
Files.exists(Path.of("foo")) || Path.of("foo").toFile().mkdirs(),
!Files.exists(Path.of("bar")) && !Path.of("bar").toFile().mkdirs());
}
ImmutableSet<Boolean> testFileMkDirsFileExists() {
return ImmutableSet.of(
new File("foo").exists() || new File("foo").mkdirs(),
!new File("bar").exists() && !new File("bar").mkdirs());
}
}

View File

@@ -39,16 +39,4 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return Files.createTempFile(new File("baz").toPath(), "foo", "bar").toFile();
}
ImmutableSet<Boolean> testPathToFileMkDirsFilesExists() {
return ImmutableSet.of(
Path.of("foo").toFile().mkdirs() || Files.exists(Path.of("foo")),
!Path.of("bar").toFile().mkdirs() && !Files.exists(Path.of("bar")));
}
ImmutableSet<Boolean> testFileMkDirsFileExists() {
return ImmutableSet.of(
new File("foo").mkdirs() || new File("foo").exists(),
!new File("bar").mkdirs() && !new File("bar").exists());
}
}

View File

@@ -143,7 +143,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(
Mono.just(1).ignoreElement().thenReturn("foo"),
Mono.just(2).then().thenReturn("bar"),
Mono.just(3).then(Mono.just("baz")));
Mono.just(3).then(Mono.just("baz")),
Mono.empty().thenReturn("qux"));
}
Mono<Boolean> testMonoThenReturnFalse() {
return Mono.empty().hasElement();
}
Mono<Optional<Object>> testMonoThenReturnOptionalEmpty() {
return Mono.empty().singleOptional();
}
Flux<Integer> testFluxTake() {
@@ -188,12 +197,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Flux<Integer>> testFluxJust() {
return ImmutableSet.of(
Flux.range(0, 1),
Mono.just(2).flux(),
Mono.just(3).repeat().take(1),
Flux.fromIterable(ImmutableList.of(4)),
Flux.fromIterable(ImmutableSet.of(5)));
return ImmutableSet.of(Flux.range(0, 1), Mono.just(2).repeat().take(1));
}
ImmutableSet<Mono<?>> testMonoIdentity() {
@@ -201,7 +205,6 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Mono.just(1).switchIfEmpty(Mono.empty()),
Mono.just(2).flux().next(),
Mono.just(3).flux().singleOrEmpty(),
Mono.<Void>empty().ignoreElement(),
Mono.<Void>empty().then(),
Mono.<ImmutableList<String>>empty().map(ImmutableList::copyOf));
}
@@ -347,11 +350,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Mono<Void>> testMonoThen() {
return ImmutableSet.of(
Mono.just("foo").ignoreElement().then(),
Mono.just("bar").flux().then(),
Mono.when(Mono.just("baz")),
Mono.whenDelayError(Mono.just("qux")));
return ImmutableSet.of(Mono.just("foo").ignoreElement().then(), Mono.just("bar").flux().then());
}
ImmutableSet<Mono<Void>> testFluxThen() {
@@ -377,14 +376,18 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Mono.just("foo").thenMany(Mono.just("bar"));
}
Flux<String> testFluxThenMany() {
return Flux.just("foo").ignoreElements().thenMany(Flux.just("bar"));
ImmutableSet<Flux<String>> testFluxThenMany() {
return ImmutableSet.of(
Flux.just("foo").ignoreElements().thenMany(Flux.just("bar")),
Flux.<String>empty().concatWith(Mono.just("baz")),
Flux.<String>empty().switchIfEmpty(Flux.just("qux", "quux")));
}
ImmutableSet<Mono<?>> testMonoThenMono() {
return ImmutableSet.of(
Mono.just("foo").ignoreElement().then(Mono.just("bar")),
Mono.just("baz").flux().then(Mono.just("qux")),
Mono.empty().switchIfEmpty(Mono.never()),
Mono.just("quux").thenEmpty(Mono.<Void>empty()));
}
@@ -397,18 +400,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Mono<Optional<String>>> testMonoSingleOptional() {
return ImmutableSet.of(
Mono.just("foo").flux().collect(toOptional()),
Mono.just("bar").map(Optional::of),
Mono.just("baz").singleOptional().defaultIfEmpty(Optional.empty()),
Mono.just("quux").singleOptional().switchIfEmpty(Mono.just(Optional.empty())),
Mono.just("quuz").transform(Mono::singleOptional));
Mono.just("bar").map(Optional::of).defaultIfEmpty(Optional.empty()),
Mono.just("baz").transform(Mono::singleOptional));
}
Mono<Number> testMonoCast() {
return Mono.just(1).map(Number.class::cast);
ImmutableSet<Mono<Number>> testMonoCast() {
return ImmutableSet.of(Mono.just(1).map(Number.class::cast), Mono.empty().ofType(Number.class));
}
Flux<Number> testFluxCast() {
return Flux.just(1).map(Number.class::cast);
ImmutableSet<Flux<Number>> testFluxCast() {
return ImmutableSet.of(Flux.just(1).map(Number.class::cast), Flux.empty().ofType(Number.class));
}
Mono<Number> testMonoOfType() {

View File

@@ -148,7 +148,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(
Mono.just(1).thenReturn("foo"),
Mono.just(2).thenReturn("bar"),
Mono.just(3).thenReturn("baz"));
Mono.just(3).thenReturn("baz"),
Mono.empty().thenReturn("qux"));
}
Mono<Boolean> testMonoThenReturnFalse() {
return Mono.empty().thenReturn(false);
}
Mono<Optional<Object>> testMonoThenReturnOptionalEmpty() {
return Mono.empty().thenReturn(Optional.empty());
}
Flux<Integer> testFluxTake() {
@@ -192,7 +201,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Flux<Integer>> testFluxJust() {
return ImmutableSet.of(Flux.just(0), Flux.just(2), Flux.just(3), Flux.just(4), Flux.just(5));
return ImmutableSet.of(Flux.just(0), Flux.just(2));
}
ImmutableSet<Mono<?>> testMonoIdentity() {
@@ -201,7 +210,6 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Mono.just(2),
Mono.just(3),
Mono.<Void>empty(),
Mono.<Void>empty(),
Mono.<ImmutableList<String>>empty());
}
@@ -340,11 +348,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Mono<Void>> testMonoThen() {
return ImmutableSet.of(
Mono.just("foo").then(),
Mono.just("bar").then(),
Mono.just("baz").then(),
Mono.just("qux").then());
return ImmutableSet.of(Mono.just("foo").then(), Mono.just("bar").then());
}
ImmutableSet<Mono<Void>> testFluxThen() {
@@ -368,14 +372,18 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Mono.just("foo").then(Mono.just("bar")).flux();
}
Flux<String> testFluxThenMany() {
return Flux.just("foo").thenMany(Flux.just("bar"));
ImmutableSet<Flux<String>> testFluxThenMany() {
return ImmutableSet.of(
Flux.just("foo").thenMany(Flux.just("bar")),
Flux.<String>empty().thenMany(Mono.just("baz")),
Flux.<String>empty().thenMany(Flux.just("qux", "quux")));
}
ImmutableSet<Mono<?>> testMonoThenMono() {
return ImmutableSet.of(
Mono.just("foo").then(Mono.just("bar")),
Mono.just("baz").then(Mono.just("qux")),
Mono.empty().then(Mono.never()),
Mono.just("quux").then(Mono.<Void>empty()));
}
@@ -388,17 +396,15 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(
Mono.just("foo").singleOptional(),
Mono.just("bar").singleOptional(),
Mono.just("baz").singleOptional(),
Mono.just("quux").singleOptional(),
Mono.just("quuz").singleOptional());
Mono.just("baz").singleOptional());
}
Mono<Number> testMonoCast() {
return Mono.just(1).cast(Number.class);
ImmutableSet<Mono<Number>> testMonoCast() {
return ImmutableSet.of(Mono.just(1).cast(Number.class), Mono.empty().cast(Number.class));
}
Flux<Number> testFluxCast() {
return Flux.just(1).cast(Number.class);
ImmutableSet<Flux<Number>> testFluxCast() {
return ImmutableSet.of(Flux.just(1).cast(Number.class), Flux.empty().cast(Number.class));
}
Mono<Number> testMonoOfType() {

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
@@ -24,9 +23,7 @@ final class SuggestedFixRulesTest implements RefasterRuleCollectionTestCase {
}
SuggestedFix testSuggestedFixSwap() {
return SuggestedFix.builder()
.swap((Tree) null, (ExpressionTree) null, (VisitorState) null)
.build();
return SuggestedFix.builder().swap((Tree) null, (ExpressionTree) null).build();
}
SuggestedFix testSuggestedFixPrefixWith() {

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
@@ -24,7 +23,7 @@ final class SuggestedFixRulesTest implements RefasterRuleCollectionTestCase {
}
SuggestedFix testSuggestedFixSwap() {
return SuggestedFix.swap((Tree) null, (ExpressionTree) null, (VisitorState) null);
return SuggestedFix.swap((Tree) null, (ExpressionTree) null);
}
SuggestedFix testSuggestedFixPrefixWith() {

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-experimental</artifactId>

View File

@@ -29,7 +29,6 @@ import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type;
import java.util.List;
import java.util.Optional;
@@ -127,7 +126,7 @@ public final class MethodReferenceUsage extends BugChecker implements LambdaExpr
return Optional.empty();
}
Symbol sym = ASTHelpers.getSymbol(subTree);
Symbol sym = ASTHelpers.getSymbol(methodSelect);
return ASTHelpers.isStatic(sym)
? constructFix(lambdaExpr, sym.owner, methodSelect)
: constructFix(lambdaExpr, "this", methodSelect);
@@ -201,8 +200,7 @@ public final class MethodReferenceUsage extends BugChecker implements LambdaExpr
Name sName = target.getSimpleName();
Optional<SuggestedFix.Builder> fix = constructFix(lambdaExpr, sName, methodName);
PackageSymbol pkg = ASTHelpers.enclosingPackage(target);
if (pkg != null && !"java.lang".equals(pkg.toString())) {
if (!"java.lang".equals(ASTHelpers.enclosingPackage(target).toString())) {
Name fqName = target.getQualifiedName();
if (!sName.equals(fqName)) {
return fix.map(b -> b.addImport(fqName.toString()));

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-guidelines</artifactId>

View File

@@ -46,6 +46,7 @@ import java.util.Set;
import java.util.function.Consumer;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Modifier;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.utils.SourceCode;
@@ -101,8 +102,7 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
AnnotationTree migrationAnnotation = migrationAnnotations.onlyMatchingNode();
AnnotationMirror annotationMirror = ASTHelpers.getAnnotationMirror(migrationAnnotation);
TypeSymbol migratedType = getMigratedType(annotationMirror);
if (migratedType.asType().isPrimitive()
|| !(migratedType instanceof ClassSymbol migratedClass)) {
if (migratedType.asType().isPrimitive() || !(migratedType instanceof ClassSymbol)) {
return buildDescription(migrationAnnotation)
.setMessage(String.format("Migration of type '%s' is unsupported", migratedType))
.build();
@@ -111,7 +111,7 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
ImmutableList<String> methodsClaimedUnmigrated = getMethodsClaimedUnmigrated(annotationMirror);
ImmutableList<String> unmigratedMethods =
getMethodsDefinitelyUnmigrated(
tree, migratedClass, signatureOrder(methodsClaimedUnmigrated), state);
tree, (ClassSymbol) migratedType, signatureOrder(methodsClaimedUnmigrated), state);
if (unmigratedMethods.equals(methodsClaimedUnmigrated)) {
return Description.NO_MATCH;
@@ -160,11 +160,17 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
.getValue().stream().map(a -> a.getValue().toString()).collect(toImmutableList());
}
// XXX: Once only JDK 14 and above are supported, change the
// `m.getModifiers().contains(Modifier.PUBLIC)` check to just `m.isPublic()`.
private static ImmutableList<String> getMethodsDefinitelyUnmigrated(
ClassTree tree, ClassSymbol migratedType, Comparator<String> comparator, VisitorState state) {
Set<MethodSymbol> publicMethods =
Streams.stream(
migratedType.members().getSymbols(m -> m.isPublic() && m instanceof MethodSymbol))
ASTHelpers.scope(migratedType.members())
.getSymbols(
m ->
m.getModifiers().contains(Modifier.PUBLIC)
&& m instanceof MethodSymbol))
.map(MethodSymbol.class::cast)
.collect(toCollection(HashSet::new));

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-utils</artifactId>

View File

@@ -1,7 +1,5 @@
package tech.picnic.errorprone.utils;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
@@ -117,15 +115,9 @@ public final class AnnotationAttributeMatcher implements Serializable {
}
private static String extractAttributeName(ExpressionTree expr) {
if (!(expr instanceof AssignmentTree assignment)) {
return "value";
}
return requireNonNull(
ASTHelpers.getSymbol(assignment.getVariable()),
"Missing symbol for annotation attribute")
.getSimpleName()
.toString();
return (expr instanceof AssignmentTree assignment)
? ASTHelpers.getSymbol(assignment.getVariable()).getSimpleName().toString()
: "value";
}
// XXX: The caller of this method can be implemented more efficiently in case of a "wholeTypes"

View File

@@ -303,7 +303,14 @@ final class SourceCodeTest {
@Override
public Description matchLiteral(LiteralTree tree, VisitorState state) {
// XXX: The character conversion is a workaround for the fact that `ASTHelpers#constValue`
// returns an `Integer` value for `char` constants.
return Optional.ofNullable(ASTHelpers.constValue(tree))
.map(
constant ->
ASTHelpers.isSubtype(ASTHelpers.getType(tree), state.getSymtab().charType, state)
? (char) (int) constant
: constant)
.map(constant -> describeMatch(tree, addComment(tree, constant, state)))
.orElse(Description.NO_MATCH);
}

View File

@@ -89,63 +89,15 @@
}
return new CollectdReporter(
registry,
@@ -177,7 +172,7 @@ public class CollectdReporter extends ScheduledReporter {
}
}
- private static final Logger LOG = LoggerFactory.getLogger(CollectdReporter.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(CollectdReporter.class);
private static final String REPORTER_NAME = "collectd-reporter";
private static final String FALLBACK_HOST_NAME = "localhost";
private static final String COLLECTD_TYPE_GAUGE = "gauge";
@@ -224,7 +219,7 @@ public class CollectdReporter extends ScheduledReporter {
try {
return InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
- LOG.error("Failed to lookup local host name: {}", e.getMessage(), e);
+ LOGGER.error("Failed to lookup local host name: {}", e.getMessage(), e);
return FALLBACK_HOST_NAME;
}
}
@@ -263,7 +258,7 @@ public class CollectdReporter extends ScheduledReporter {
serializeTimer(metaData.plugin(entry.getKey().getKey()), entry.getValue());
}
} catch (IOException e) {
- LOG.warn("Unable to report to Collectd", e);
+ LOGGER.warn("Unable to report to Collectd", e);
} finally {
disconnect(sender);
}
@@ -279,7 +274,7 @@ public class CollectdReporter extends ScheduledReporter {
try {
sender.disconnect();
} catch (Exception e) {
- LOG.warn("Error disconnecting from Collectd", e);
+ LOGGER.warn("Error disconnecting from Collectd", e);
}
}
@@ -302,9 +297,9 @@ public class CollectdReporter extends ScheduledReporter {
@@ -302,7 +297,7 @@ public class CollectdReporter extends ScheduledReporter {
try {
writer.write(metaData, value);
} catch (RuntimeException e) {
- LOG.warn("Failed to process metric '" + metaData.getPlugin() + "': " + e.getMessage());
+ LOGGER.warn("Failed to process metric '{}': {}", metaData.getPlugin(), e.getMessage());
+ LOG.warn("Failed to process metric '{}': {}", metaData.getPlugin(), e.getMessage());
} catch (IOException e) {
- LOG.error("Failed to send metric to collectd", e);
+ LOGGER.error("Failed to send metric to collectd", e);
LOG.error("Failed to send metric to collectd", e);
}
}
@@ -314,7 +309,7 @@ public class CollectdReporter extends ScheduledReporter {
} else if (metric.getValue() instanceof Boolean) {
write(metaData.typeInstance("value").get(), ((Boolean) metric.getValue()) ? 1 : 0);
} else {
- LOG.warn(
+ LOGGER.warn(
"Failed to process metric '{}'. Unsupported gauge of type: {} ",
metaData.get().getPlugin(),
metric.getValue().getClass().getName());
@@ -336,9 +331,9 @@ public class CollectdReporter extends ScheduledReporter {
private void serializeHistogram(MetaData.Builder metaData, Histogram metric) {
final Snapshot snapshot = metric.getSnapshot();
@@ -524,6 +476,26 @@
}
/**
--- a/metrics-core/src/main/java/io/dropwizard/metrics5/CsvReporter.java
+++ b/metrics-core/src/main/java/io/dropwizard/metrics5/CsvReporter.java
@@ -179,7 +179,7 @@ public class CsvReporter extends ScheduledReporter {
}
}
- private static final Logger LOGGER = LoggerFactory.getLogger(CsvReporter.class);
+ private static final Logger LOG = LoggerFactory.getLogger(CsvReporter.class);
private final File directory;
private final Locale locale;
@@ -391,7 +391,7 @@ public class CsvReporter extends ScheduledReporter {
}
}
} catch (IOException e) {
- LOGGER.warn("Error writing to {}", name, e);
+ LOG.warn("Error writing to {}", name, e);
}
}
--- a/metrics-core/src/main/java/io/dropwizard/metrics5/ExponentialMovingAverages.java
+++ b/metrics-core/src/main/java/io/dropwizard/metrics5/ExponentialMovingAverages.java
@@ -17,9 +17,9 @@ public class ExponentialMovingAverages implements MovingAverages {
@@ -1018,15 +990,6 @@
import java.util.Locale;
import java.util.Set;
import java.util.SortedMap;
@@ -24,7 +27,7 @@ import org.slf4j.LoggerFactory;
*/
public abstract class ScheduledReporter implements Closeable, Reporter {
- private static final Logger LOG = LoggerFactory.getLogger(ScheduledReporter.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledReporter.class);
/** A simple named thread factory. */
@SuppressWarnings("NullableProblems")
@@ -128,7 +131,7 @@ public abstract class ScheduledReporter implements Closeable, Reporter {
durationUnit,
executor,
@@ -1077,33 +1040,6 @@
protected ScheduledFuture<?> getScheduledFuture(
long initialDelay, long period, TimeUnit unit, Runnable runnable) {
return getScheduledFuture(initialDelay, period, unit, runnable, this.executor);
@@ -225,7 +224,7 @@ public abstract class ScheduledReporter implements Closeable, Reporter {
try {
report();
} catch (Throwable ex) {
- LOG.error(
+ LOGGER.error(
"Exception thrown from {}#report. Exception was suppressed.",
ScheduledReporter.this.getClass().getSimpleName(),
ex);
@@ -250,7 +249,7 @@ public abstract class ScheduledReporter implements Closeable, Reporter {
try {
report();
} catch (Exception e) {
- LOG.warn("Final reporting of metrics failed.", e);
+ LOGGER.warn("Final reporting of metrics failed.", e);
}
}
@@ -261,7 +260,7 @@ public abstract class ScheduledReporter implements Closeable, Reporter {
executor.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
- LOG.warn("ScheduledExecutorService did not terminate.");
+ LOGGER.warn("ScheduledExecutorService did not terminate.");
}
}
} catch (InterruptedException ie) {
--- a/metrics-core/src/main/java/io/dropwizard/metrics5/SharedMetricRegistries.java
+++ b/metrics-core/src/main/java/io/dropwizard/metrics5/SharedMetricRegistries.java
@@ -1,5 +1,7 @@
@@ -1264,15 +1200,32 @@
import java.util.ArrayList;
import java.util.List;
@@ -15,7 +14,7 @@ import org.junit.jupiter.api.Test;
@@ -15,8 +14,8 @@ import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class CachedGaugeTest {
- private static final Logger LOGGER = LoggerFactory.getLogger(CachedGaugeTest.class);
+final class CachedGaugeTest {
private static final Logger LOGGER = LoggerFactory.getLogger(CachedGaugeTest.class);
+ private static final Logger LOG = LoggerFactory.getLogger(CachedGaugeTest.class);
private static final int THREAD_COUNT = 10;
private static final long RUNNING_TIME_MILLIS = TimeUnit.SECONDS.toMillis(10);
@@ -100,12 +99,12 @@ class CachedGaugeTest {
Integer newValue = shortTimeoutGauge.getValue();
if (newValue == null) {
- LOGGER.warn("Cached gauge returned null value");
+ LOG.warn("Cached gauge returned null value");
return false;
}
if (newValue < lastValue) {
- LOGGER.error(
+ LOG.error(
"Cached gauge returned stale value, last: {}, new: {}",
lastValue,
newValue);
@@ -122,7 +121,7 @@ class CachedGaugeTest {
}
@@ -1946,16 +1899,29 @@
assertThat(histogram.getSnapshot()).isEqualTo(snapshot);
--- a/metrics-core/src/test/java/io/dropwizard/metrics5/InstrumentedExecutorServiceTest.java
+++ b/metrics-core/src/test/java/io/dropwizard/metrics5/InstrumentedExecutorServiceTest.java
@@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test;
@@ -19,10 +19,9 @@ import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class InstrumentedExecutorServiceTest {
+final class InstrumentedExecutorServiceTest {
private static final Logger LOGGER =
LoggerFactory.getLogger(InstrumentedExecutorServiceTest.class);
@@ -115,8 +115,8 @@ class InstrumentedExecutorServiceTest {
- private static final Logger LOGGER =
- LoggerFactory.getLogger(InstrumentedExecutorServiceTest.class);
+ private static final Logger LOG = LoggerFactory.getLogger(InstrumentedExecutorServiceTest.class);
private ExecutorService executor;
private MetricRegistry registry;
private InstrumentedExecutorService instrumentedExecutorService;
@@ -48,7 +47,7 @@ class InstrumentedExecutorServiceTest {
void tearDown() throws Exception {
instrumentedExecutorService.shutdown();
if (!instrumentedExecutorService.awaitTermination(2, TimeUnit.SECONDS)) {
- LOGGER.error("InstrumentedExecutorService did not terminate.");
+ LOG.error("InstrumentedExecutorService did not terminate.");
}
}
@@ -115,8 +114,8 @@ class InstrumentedExecutorServiceTest {
assertThat(idle.getSnapshot().size()).isEqualTo(1);
}
@@ -1965,7 +1931,7 @@
void reportsTasksInformationForThreadPoolExecutor() throws Exception {
executor =
new ThreadPoolExecutor(4, 16, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(32));
@@ -180,7 +180,7 @@ class InstrumentedExecutorServiceTest {
@@ -180,7 +179,7 @@ class InstrumentedExecutorServiceTest {
}
@Test
@@ -1974,7 +1940,7 @@
executor =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1));
instrumentedExecutorService = new InstrumentedExecutorService(executor, registry, "tp");
@@ -207,7 +207,7 @@ class InstrumentedExecutorServiceTest {
@@ -207,7 +206,7 @@ class InstrumentedExecutorServiceTest {
}
@Test
@@ -1983,7 +1949,7 @@
executor =
new ThreadPoolExecutor(4, 16, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(32));
instrumentedExecutorService = new InstrumentedExecutorService(executor, registry, "stp");
@@ -236,8 +236,8 @@ class InstrumentedExecutorServiceTest {
@@ -236,8 +235,8 @@ class InstrumentedExecutorServiceTest {
MetricRegistry.name("stp", "tasks.capacity"));
}
@@ -1993,7 +1959,7 @@
void reportsTasksInformationForForkJoinPool() throws Exception {
executor = Executors.newWorkStealingPool(4);
instrumentedExecutorService = new InstrumentedExecutorService(executor, registry, "fjp");
@@ -291,7 +291,7 @@ class InstrumentedExecutorServiceTest {
@@ -291,7 +290,7 @@ class InstrumentedExecutorServiceTest {
}
@Test
@@ -2004,15 +1970,17 @@
--- a/metrics-core/src/test/java/io/dropwizard/metrics5/InstrumentedScheduledExecutorServiceTest.java
+++ b/metrics-core/src/test/java/io/dropwizard/metrics5/InstrumentedScheduledExecutorServiceTest.java
@@ -13,7 +13,7 @@ import org.junit.jupiter.api.Test;
@@ -13,8 +13,8 @@ import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class InstrumentedScheduledExecutorServiceTest {
- private static final Logger LOGGER =
+final class InstrumentedScheduledExecutorServiceTest {
private static final Logger LOGGER =
+ private static final Logger LOG =
LoggerFactory.getLogger(InstrumentedScheduledExecutorServiceTest.class);
private final ScheduledExecutorService scheduledExecutor =
@@ -35,17 +35,17 @@ class InstrumentedScheduledExecutorServiceTest {
private final Histogram percentOfPeriod = registry.histogram("xs.scheduled.percent-of-period");
@@ -2370,6 +2338,15 @@
assertThat(completed.getCount()).isNotEqualTo(0);
assertThat(duration.getCount()).isNotEqualTo(0);
assertThat(duration.getSnapshot().size()).isNotEqualTo(0);
@@ -322,7 +322,7 @@ class InstrumentedScheduledExecutorServiceTest {
void tearDown() throws Exception {
instrumentedScheduledExecutor.shutdown();
if (!instrumentedScheduledExecutor.awaitTermination(2, TimeUnit.SECONDS)) {
- LOGGER.error("InstrumentedScheduledExecutorService did not terminate.");
+ LOG.error("InstrumentedScheduledExecutorService did not terminate.");
}
}
}
--- a/metrics-core/src/test/java/io/dropwizard/metrics5/InstrumentedThreadFactoryTest.java
+++ b/metrics-core/src/test/java/io/dropwizard/metrics5/InstrumentedThreadFactoryTest.java
@@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit;
@@ -3824,6 +3801,15 @@
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
@@ -29,7 +32,7 @@ public class Graphite implements GraphiteSender {
private Writer writer;
private int failures;
- private static final Logger LOGGER = LoggerFactory.getLogger(Graphite.class);
+ private static final Logger LOG = LoggerFactory.getLogger(Graphite.class);
/**
* Creates a new client which connects to the given address using the default {@link
@@ -63,13 +66,9 @@ public class Graphite implements GraphiteSender {
* @param charset the character set used by the server
*/
@@ -3851,6 +3837,24 @@
InetSocketAddress address = this.address;
// the previous dns retry logic did not work, as address.getAddress would always return the
// cached value
@@ -178,7 +175,7 @@ public class Graphite implements GraphiteSender {
writer.close();
}
} catch (IOException ex) {
- LOGGER.debug("Error closing writer", ex);
+ LOG.debug("Error closing writer", ex);
} finally {
this.writer = null;
}
@@ -188,7 +185,7 @@ public class Graphite implements GraphiteSender {
socket.close();
}
} catch (IOException ex) {
- LOGGER.debug("Error closing socket", ex);
+ LOG.debug("Error closing socket", ex);
} finally {
this.socket = null;
}
--- a/metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteRabbitMQ.java
+++ b/metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteRabbitMQ.java
@@ -1,5 +1,6 @@
@@ -3919,7 +3923,39 @@
this.addMetricAttributesAsTags = false;
this.floatingPointFormatter = DEFAULT_FP_FORMATTER;
}
@@ -455,9 +453,9 @@ public class GraphiteReporter extends ScheduledReporter {
@@ -249,7 +247,7 @@ public class GraphiteReporter extends ScheduledReporter {
}
}
- private static final Logger LOGGER = LoggerFactory.getLogger(GraphiteReporter.class);
+ private static final Logger LOG = LoggerFactory.getLogger(GraphiteReporter.class);
// the Carbon plaintext format is pretty underspecified, but it seems like it just wants
// US-formatted digits
private static final DoubleFunction<String> DEFAULT_FP_FORMATTER =
@@ -430,12 +428,12 @@ public class GraphiteReporter extends ScheduledReporter {
}
graphite.flush();
} catch (IOException e) {
- LOGGER.warn("Unable to report to Graphite", graphite, e);
+ LOG.warn("Unable to report to Graphite", graphite, e);
} finally {
try {
graphite.close();
} catch (IOException e1) {
- LOGGER.warn("Error closing Graphite", graphite, e1);
+ LOG.warn("Error closing Graphite", graphite, e1);
}
}
}
@@ -448,16 +446,16 @@ public class GraphiteReporter extends ScheduledReporter {
try {
graphite.close();
} catch (IOException e) {
- LOGGER.debug("Error disconnecting from Graphite", graphite, e);
+ LOG.debug("Error disconnecting from Graphite", graphite, e);
}
}
}
private void reportTimer(MetricName name, Timer timer, long timestamp) throws IOException {
final Snapshot snapshot = timer.getSnapshot();
@@ -3981,6 +4017,15 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.BufferedWriter;
@@ -48,7 +49,7 @@ public class PickledGraphite implements GraphiteSender {
QUOTE = '\'',
LF = '\n';
- private static final Logger LOGGER = LoggerFactory.getLogger(PickledGraphite.class);
+ private static final Logger LOG = LoggerFactory.getLogger(PickledGraphite.class);
private static final int DEFAULT_BATCH_SIZE = 100;
private int batchSize;
@@ -173,9 +174,7 @@ public class PickledGraphite implements GraphiteSender {
@Override
@@ -4001,6 +4046,17 @@
try {
byte[] payload = pickleMetrics(metrics);
byte[] header = ByteBuffer.allocate(4).putInt(payload.length).array();
@@ -260,8 +259,8 @@ public class PickledGraphite implements GraphiteSender {
outputStream.write(payload);
outputStream.flush();
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Wrote {} metrics", metrics.size());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Wrote {} metrics", metrics.size());
}
} catch (IOException e) {
this.failures++;
--- a/metrics-graphite/src/test/java/io/dropwizard/metrics5/graphite/GraphiteRabbitMQTest.java
+++ b/metrics-graphite/src/test/java/io/dropwizard/metrics5/graphite/GraphiteRabbitMQTest.java
@@ -8,7 +8,6 @@ import static org.mockito.Mockito.anyString;
@@ -4419,6 +4475,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -27,7 +29,7 @@ import org.slf4j.LoggerFactory;
/** A registry for health checks. */
public class HealthCheckRegistry {
- private static final Logger LOGGER = LoggerFactory.getLogger(HealthCheckRegistry.class);
+ private static final Logger LOG = LoggerFactory.getLogger(HealthCheckRegistry.class);
private static final int ASYNC_EXECUTOR_POOL_SIZE = 2;
private final ConcurrentMap<String, HealthCheck> healthChecks;
@@ -92,9 +94,8 @@ public class HealthCheckRegistry {
public void register(String name, HealthCheck healthCheck) {
HealthCheck registered;
@@ -4449,7 +4514,13 @@
}
/**
@@ -222,7 +223,7 @@ public class HealthCheckRegistry {
@@ -217,12 +218,12 @@ public class HealthCheckRegistry {
try {
results.put(entry.getKey(), entry.getValue().get());
} catch (Exception e) {
- LOGGER.warn("Error executing health check {}", entry.getKey(), e);
+ LOG.warn("Error executing health check {}", entry.getKey(), e);
results.put(entry.getKey(), HealthCheck.Result.unhealthy(e));
}
}
@@ -5286,6 +5357,39 @@
}
/**
@@ -196,7 +196,7 @@ public class InfluxDbReporter extends GarbageFreeScheduledReporter {
}
}
- private static final Logger LOGGER = LoggerFactory.getLogger(InfluxDbReporter.class);
+ private static final Logger LOG = LoggerFactory.getLogger(InfluxDbReporter.class);
private static final String VALUE = "value";
private final Clock clock;
@@ -279,12 +279,12 @@ public class InfluxDbReporter extends GarbageFreeScheduledReporter {
}
sender.flush();
} catch (IOException e) {
- LOGGER.warn("Unable to report to InfluxDb", sender, e);
+ LOG.warn("Unable to report to InfluxDb", sender, e);
} finally {
try {
sender.disconnect();
} catch (IOException e) {
- LOGGER.warn("Error disconnecting InfluxDb", sender, e);
+ LOG.warn("Error disconnecting InfluxDb", sender, e);
}
}
}
@@ -297,7 +297,7 @@ public class InfluxDbReporter extends GarbageFreeScheduledReporter {
try {
sender.close();
} catch (IOException e) {
- LOGGER.debug("Error disconnecting from InfluxDb", e);
+ LOG.debug("Error disconnecting from InfluxDb", e);
}
}
}
--- a/metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbUdpSender.java
+++ b/metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbUdpSender.java
@@ -1,5 +1,7 @@
@@ -5961,6 +6065,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -33,7 +33,7 @@ public class JCacheGaugeSet implements MetricSet {
private static final String M_BEAN_COORDINATES =
"javax.cache:type=CacheStatistics,CacheManager=*,Cache=*";
- private static final Logger LOGGER = LoggerFactory.getLogger(JCacheGaugeSet.class);
+ private static final Logger LOG = LoggerFactory.getLogger(JCacheGaugeSet.class);
@Override
public Map<MetricName, Metric> getMetrics() {
@@ -52,7 +52,7 @@ public class JCacheGaugeSet implements MetricSet {
}
}
@@ -5970,6 +6083,15 @@
}
private Set<ObjectInstance> getCacheBeans() {
@@ -60,7 +60,7 @@ public class JCacheGaugeSet implements MetricSet {
return ManagementFactory.getPlatformMBeanServer()
.queryMBeans(ObjectName.getInstance(M_BEAN_COORDINATES), null);
} catch (MalformedObjectNameException e) {
- LOGGER.error("Unable to retrieve {}. Are JCache statistics enabled?", M_BEAN_COORDINATES);
+ LOG.error("Unable to retrieve {}. Are JCache statistics enabled?", M_BEAN_COORDINATES);
throw new RuntimeException(e);
}
}
--- a/metrics-jcache/src/test/java/JCacheGaugeSetTest.java
+++ b/metrics-jcache/src/test/java/JCacheGaugeSetTest.java
@@ -11,7 +11,7 @@ import org.junit.jupiter.api.AfterEach;
@@ -8339,11 +8461,11 @@
private static final char[] QUOTABLE_CHARS = new char[] {',', '=', ':', '"'};
- private static final Logger LOGGER = LoggerFactory.getLogger(JmxReporter.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultObjectNameFactory.class);
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultObjectNameFactory.class);
@Override
public ObjectName createName(String type, String domain, MetricName name) {
@@ -38,9 +38,8 @@ public class DefaultObjectNameFactory implements ObjectNameFactory {
@@ -38,14 +38,13 @@ public class DefaultObjectNameFactory implements ObjectNameFactory {
|| shouldQuote(objectName.getKeyProperty("type"))) {
properties.put("type", ObjectName.quote(type));
}
@@ -8354,6 +8476,12 @@
} catch (MalformedObjectNameException e) {
try {
return new ObjectName(domain, "name", ObjectName.quote(name.getKey()));
} catch (MalformedObjectNameException e1) {
- LOGGER.warn("Unable to register {} {}", type, name, e1);
+ LOG.warn("Unable to register {} {}", type, name, e1);
throw new RuntimeException(e1);
}
}
--- a/metrics-jmx/src/main/java/io/dropwizard/metrics5/jmx/JmxReporter.java
+++ b/metrics-jmx/src/main/java/io/dropwizard/metrics5/jmx/JmxReporter.java
@@ -1,5 +1,9 @@
@@ -8414,6 +8542,147 @@
return this;
}
@@ -159,7 +160,7 @@ public class JmxReporter implements Reporter, Closeable {
}
}
- private static final Logger LOGGER = LoggerFactory.getLogger(JmxReporter.class);
+ private static final Logger LOG = LoggerFactory.getLogger(JmxReporter.class);
@SuppressWarnings("UnusedDeclaration")
public interface MetricMBean {
@@ -570,9 +571,9 @@ public class JmxReporter implements Reporter, Closeable {
registerMBean(new JmxGauge(gauge, objectName), objectName);
}
} catch (InstanceAlreadyExistsException e) {
- LOGGER.debug("Unable to register gauge", e);
+ LOG.debug("Unable to register gauge", e);
} catch (JMException e) {
- LOGGER.warn("Unable to register gauge", e);
+ LOG.warn("Unable to register gauge", e);
}
}
@@ -582,9 +583,9 @@ public class JmxReporter implements Reporter, Closeable {
final ObjectName objectName = createName("gauges", name);
unregisterMBean(objectName);
} catch (InstanceNotFoundException e) {
- LOGGER.debug("Unable to unregister gauge", e);
+ LOG.debug("Unable to unregister gauge", e);
} catch (MBeanRegistrationException e) {
- LOGGER.warn("Unable to unregister gauge", e);
+ LOG.warn("Unable to unregister gauge", e);
}
}
@@ -596,9 +597,9 @@ public class JmxReporter implements Reporter, Closeable {
registerMBean(new JmxCounter(counter, objectName), objectName);
}
} catch (InstanceAlreadyExistsException e) {
- LOGGER.debug("Unable to register counter", e);
+ LOG.debug("Unable to register counter", e);
} catch (JMException e) {
- LOGGER.warn("Unable to register counter", e);
+ LOG.warn("Unable to register counter", e);
}
}
@@ -608,9 +609,9 @@ public class JmxReporter implements Reporter, Closeable {
final ObjectName objectName = createName("counters", name);
unregisterMBean(objectName);
} catch (InstanceNotFoundException e) {
- LOGGER.debug("Unable to unregister counter", e);
+ LOG.debug("Unable to unregister counter", e);
} catch (MBeanRegistrationException e) {
- LOGGER.warn("Unable to unregister counter", e);
+ LOG.warn("Unable to unregister counter", e);
}
}
@@ -622,9 +623,9 @@ public class JmxReporter implements Reporter, Closeable {
registerMBean(new JmxHistogram(histogram, objectName), objectName);
}
} catch (InstanceAlreadyExistsException e) {
- LOGGER.debug("Unable to register histogram", e);
+ LOG.debug("Unable to register histogram", e);
} catch (JMException e) {
- LOGGER.warn("Unable to register histogram", e);
+ LOG.warn("Unable to register histogram", e);
}
}
@@ -634,9 +635,9 @@ public class JmxReporter implements Reporter, Closeable {
final ObjectName objectName = createName("histograms", name);
unregisterMBean(objectName);
} catch (InstanceNotFoundException e) {
- LOGGER.debug("Unable to unregister histogram", e);
+ LOG.debug("Unable to unregister histogram", e);
} catch (MBeanRegistrationException e) {
- LOGGER.warn("Unable to unregister histogram", e);
+ LOG.warn("Unable to unregister histogram", e);
}
}
@@ -649,9 +650,9 @@ public class JmxReporter implements Reporter, Closeable {
new JmxMeter(meter, objectName, timeUnits.rateFor(name.getKey())), objectName);
}
} catch (InstanceAlreadyExistsException e) {
- LOGGER.debug("Unable to register meter", e);
+ LOG.debug("Unable to register meter", e);
} catch (JMException e) {
- LOGGER.warn("Unable to register meter", e);
+ LOG.warn("Unable to register meter", e);
}
}
@@ -661,9 +662,9 @@ public class JmxReporter implements Reporter, Closeable {
final ObjectName objectName = createName("meters", name);
unregisterMBean(objectName);
} catch (InstanceNotFoundException e) {
- LOGGER.debug("Unable to unregister meter", e);
+ LOG.debug("Unable to unregister meter", e);
} catch (MBeanRegistrationException e) {
- LOGGER.warn("Unable to unregister meter", e);
+ LOG.warn("Unable to unregister meter", e);
}
}
@@ -681,9 +682,9 @@ public class JmxReporter implements Reporter, Closeable {
objectName);
}
} catch (InstanceAlreadyExistsException e) {
- LOGGER.debug("Unable to register timer", e);
+ LOG.debug("Unable to register timer", e);
} catch (JMException e) {
- LOGGER.warn("Unable to register timer", e);
+ LOG.warn("Unable to register timer", e);
}
}
@@ -693,9 +694,9 @@ public class JmxReporter implements Reporter, Closeable {
final ObjectName objectName = createName("timers", name);
unregisterMBean(objectName);
} catch (InstanceNotFoundException e) {
- LOGGER.debug("Unable to unregister timer", e);
+ LOG.debug("Unable to unregister timer", e);
} catch (MBeanRegistrationException e) {
- LOGGER.warn("Unable to unregister timer", e);
+ LOG.warn("Unable to unregister timer", e);
}
}
@@ -708,9 +709,9 @@ public class JmxReporter implements Reporter, Closeable {
try {
unregisterMBean(name);
} catch (InstanceNotFoundException e) {
- LOGGER.debug("Unable to unregister metric", e);
+ LOG.debug("Unable to unregister metric", e);
} catch (MBeanRegistrationException e) {
- LOGGER.warn("Unable to unregister metric", e);
+ LOG.warn("Unable to unregister metric", e);
}
}
registered.clear();
--- a/metrics-jmx/src/test/java/io/dropwizard/metrics5/jmx/DefaultObjectNameFactoryTest.java
+++ b/metrics-jmx/src/test/java/io/dropwizard/metrics5/jmx/DefaultObjectNameFactoryTest.java
@@ -7,7 +7,7 @@ import io.dropwizard.metrics5.MetricName;
@@ -8733,7 +9002,21 @@
import java.util.HashMap;
import java.util.Map;
import javax.management.JMException;
@@ -47,6 +48,6 @@ public class BufferPoolMetricSet implements MetricSet {
@@ -19,7 +20,7 @@ import org.slf4j.LoggerFactory;
* <p>These JMX objects are only available on Java 7 and above.
*/
public class BufferPoolMetricSet implements MetricSet {
- private static final Logger LOGGER = LoggerFactory.getLogger(BufferPoolMetricSet.class);
+ private static final Logger LOG = LoggerFactory.getLogger(BufferPoolMetricSet.class);
private static final String[] ATTRIBUTES = {"Count", "MemoryUsed", "TotalCapacity"};
private static final String[] NAMES = {"count", "used", "capacity"};
private static final String[] POOLS = {"direct", "mapped"};
@@ -43,10 +44,10 @@ public class BufferPoolMetricSet implements MetricSet {
gauges.put(
MetricRegistry.name(pool, name), new JmxAttributeGauge(mBeanServer, on, attribute));
} catch (JMException ignored) {
- LOGGER.debug("Unable to load buffer pool MBeans, possibly running on Java 6");
+ LOG.debug("Unable to load buffer pool MBeans, possibly running on Java 6");
}
}
}

View File

@@ -9,9 +9,9 @@ metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java
metrics-core/src/main/java/io/dropwizard/metrics5/CsvReporter.java:[390,35] [FormatStringConcatenation] Defer string concatenation to the invoked method
metrics-core/src/main/java/io/dropwizard/metrics5/InstrumentedExecutorService.java:[244,25] [try] auto-closeable resource durationContext is never referenced in body of corresponding try statement
metrics-core/src/main/java/io/dropwizard/metrics5/InstrumentedExecutorService.java:[266,25] [try] auto-closeable resource context is never referenced in body of corresponding try statement
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[431,17] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[436,19] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[449,20] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[431,14] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[436,16] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[449,17] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-healthchecks/src/test/java/io/dropwizard/metrics5/health/HealthCheckTest.java:[189,46] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone
metrics-healthchecks/src/test/java/io/dropwizard/metrics5/health/HealthCheckTest.java:[203,46] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone
metrics-httpclient/src/test/java/io/dropwizard/metrics5/httpclient/HttpClientMetricNameStrategiesTest.java:[124,22] [deprecation] rewriteURI(URI,HttpHost,boolean) in URIUtils has been deprecated
@@ -26,8 +26,8 @@ metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/Instrumente
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpRequestExecutor.java:[49,4] [deprecation] HttpRequestExecutor(Timeout,ConnectionReuseStrategy,Http1StreamListener) in HttpRequestExecutor has been deprecated
metrics-httpclient5/src/test/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientsTest.java:[46,10] [deprecation] execute(ClassicHttpRequest) in HttpClient has been deprecated
metrics-httpclient5/src/test/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientsTest.java:[68,12] [deprecation] execute(ClassicHttpRequest) in HttpClient has been deprecated
metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbReporter.java:[282,17] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbReporter.java:[287,19] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbReporter.java:[282,14] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbReporter.java:[287,16] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-jakarta-servlets/src/test/java/io/dropwizard/metrics5/servlets/HealthCheckServletTest.java:[31,67] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone
metrics-jdbi3/src/test/java/io/dropwizard/metrics5/jdbi3/strategies/SmartNameStrategyTest.java:[18,10] [deprecation] InstrumentedTimingCollector in io.dropwizard.metrics5.jdbi3 has been deprecated
metrics-jdbi3/src/test/java/io/dropwizard/metrics5/jdbi3/strategies/SmartNameStrategyTest.java:[24,20] [deprecation] InstrumentedTimingCollector in io.dropwizard.metrics5.jdbi3 has been deprecated

View File

@@ -38,7 +38,7 @@
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>33.4.7-jre<!-- Renovate: com.google.guava:guava-bom --></version>
+ <version>33.4.0-jre<!-- Renovate: com.google.guava:guava-bom --></version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>

View File

@@ -8,7 +8,11 @@ repository='https://github.com/dropwizard/metrics.git'
revision='v5.0.0-rc22'
additional_build_flags=''
additional_source_directories=''
shared_error_prone_flags='-XepExcludedPaths:.*/target/generated-sources/.* -XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=LOGGER'
# XXX: Minimize the diff by including
# `-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=LOGGER` once such
# flags are supported in patch mode. See
# https://github.com/google/error-prone/pull/4699.
shared_error_prone_flags='-XepExcludedPaths:.*/target/generated-sources/.*'
patch_error_prone_flags=''
validation_error_prone_flags=''
validation_build_flags=''

132
pom.xml
View File

@@ -4,7 +4,7 @@
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Picnic :: Error Prone Support</name>
@@ -146,7 +146,7 @@
<error-prone.self-check-args />
<!-- The build timestamp is derived from the most recent commit
timestamp in support of reproducible builds. -->
<project.build.outputTimestamp>2025-04-14T09:36:15Z</project.build.outputTimestamp>
<project.build.outputTimestamp>2025-02-02T12:19:40Z</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
@@ -205,17 +205,17 @@
<version.auto-service>1.1.1</version.auto-service>
<version.auto-value>1.11.0</version.auto-value>
<version.error-prone>${version.error-prone-orig}</version.error-prone>
<version.error-prone-fork>${version.error-prone-orig}-picnic-1</version.error-prone-fork>
<version.error-prone-orig>2.37.0</version.error-prone-orig>
<version.error-prone-fork>${version.error-prone-orig}-picnic-2</version.error-prone-fork>
<version.error-prone-orig>2.36.0</version.error-prone-orig>
<version.error-prone-slf4j>0.1.28</version.error-prone-slf4j>
<version.guava-beta-checker>1.0</version.guava-beta-checker>
<version.jdk>17</version.jdk>
<version.maven>3.9.9</version.maven>
<version.mockito>5.17.0</version.mockito>
<version.mockito>5.15.2</version.mockito>
<version.nopen-checker>1.0.1</version.nopen-checker>
<version.nullaway>0.12.6</version.nullaway>
<version.pitest-git>2.2.1</version.pitest-git>
<version.rewrite-templating>1.25.1</version.rewrite-templating>
<version.nullaway>0.12.3</version.nullaway>
<version.pitest-git>1.1.4</version.pitest-git>
<version.rewrite-templating>1.22.1</version.rewrite-templating>
<version.surefire>3.2.3</version.surefire>
</properties>
@@ -269,7 +269,7 @@
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.18.3</version>
<version>2.18.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -303,16 +303,6 @@
<artifactId>auto-value-annotations</artifactId>
<version>${version.auto-value}</version>
</dependency>
<!-- XXX: JSR-305 (meta-)annotation usage by some dependencies
triggers NullAway to attempt to load said annotations. As such
some modules require these annotations to be on the classpath.
Periodically review whether we can drop this dependeny version
declaration. See https://github.com/uber/NullAway/issues/1171. -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
@@ -341,7 +331,7 @@
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
<version>1.26.0</version>
<version>1.25.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@@ -351,7 +341,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-bom</artifactId>
<version>33.4.7-jre</version>
<version>33.4.0-jre</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -373,14 +363,14 @@
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-bom</artifactId>
<version>1.14.6</version>
<version>1.14.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-bom</artifactId>
<version>2024.0.5</version>
<version>2024.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -397,7 +387,7 @@
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.30</version>
<version>2.2.28</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
@@ -432,7 +422,7 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.5</version>
<version>1.17.1</version>
</dependency>
<!-- Specified so that Renovate will file Maven upgrade PRs, which
subsequently will cause `maven-enforcer-plugin` to require that
@@ -445,7 +435,7 @@
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.24</version>
<version>1.9.22.1</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
@@ -457,7 +447,7 @@
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>3.49.2</version>
<version>3.49.0</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
@@ -482,7 +472,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.12.2</version>
<version>5.11.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -495,10 +485,8 @@
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-bom</artifactId>
<version>5.4.0</version>
<type>pom</type>
<scope>import</scope>
<artifactId>mongodb-driver-core</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
@@ -508,33 +496,33 @@
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-recipe-bom</artifactId>
<version>3.6.1</version>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-bom</artifactId>
<version>2.0.17</version>
<version>2.0.16</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>6.2.5</version>
<version>6.2.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>3.4.4</version>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>6.4.4</version>
<version>6.4.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -560,16 +548,6 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.arcmutate</groupId>
<artifactId>pitest-git-maven-plugin</artifactId>
<version>${version.pitest-git}</version>
</plugin>
<plugin>
<groupId>com.arcmutate</groupId>
<artifactId>pitest-github-maven-plugin</artifactId>
<version>${version.pitest-git}</version>
</plugin>
<plugin>
<groupId>com.github.ekryd.sortpom</groupId>
<artifactId>sortpom-maven-plugin</artifactId>
@@ -597,6 +575,16 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.groupcdg</groupId>
<artifactId>pitest-git-maven-plugin</artifactId>
<version>${version.pitest-git}</version>
</plugin>
<plugin>
<groupId>com.groupcdg</groupId>
<artifactId>pitest-github-maven-plugin</artifactId>
<version>${version.pitest-git}</version>
</plugin>
<plugin>
<groupId>com.spotify.fmt</groupId>
<artifactId>fmt-maven-plugin</artifactId>
@@ -620,7 +608,7 @@
<plugin>
<groupId>de.thetaphi</groupId>
<artifactId>forbiddenapis</artifactId>
<version>3.9</version>
<version>3.8</version>
<configuration>
<bundledSignatures>
<bundledSignature>jdk-internal</bundledSignature>
@@ -935,7 +923,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>10.23.0</version>
<version>10.21.2</version>
</dependency>
<dependency>
<groupId>io.spring.nohttp</groupId>
@@ -960,7 +948,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<version>3.13.0</version>
<configuration>
<annotationProcessorPaths>
<!-- XXX: Inline and drop the version
@@ -1068,7 +1056,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.4</version>
<version>3.1.3</version>
<configuration>
<retryFailedDeploymentCount>3</retryFailedDeploymentCount>
</configuration>
@@ -1146,7 +1134,7 @@
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>extra-enforcer-rules</artifactId>
<version>1.10.0</version>
<version>1.9.0</version>
</dependency>
</dependencies>
<executions>
@@ -1174,7 +1162,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.4</version>
<version>3.1.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -1310,7 +1298,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<version>3.5.2</version>
<configuration>
<includes>
<include>**/*Test.java</include>
@@ -1318,7 +1306,6 @@
<properties>
<configurationParameters>junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.timeout.threaddump.enabled=true
junit.platform.stacktrace.pruning.enabled=false</configurationParameters>
</properties>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
@@ -1455,7 +1442,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tidy-maven-plugin</artifactId>
<version>1.4.0</version>
<version>1.3.0</version>
<executions>
<execution>
<id>check-pom</id>
@@ -1507,7 +1494,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<version>0.8.12</version>
<configuration>
<excludes>
<!-- Refaster rules are tested using a custom method
@@ -1537,7 +1524,7 @@
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.19.1</version>
<version>1.18.1</version>
<configuration>
<excludedClasses>
<!-- AutoValue generated classes. -->
@@ -1559,24 +1546,24 @@
</configuration>
<dependencies>
<dependency>
<groupId>com.arcmutate</groupId>
<artifactId>base</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.arcmutate</groupId>
<artifactId>pitest-accelerator-junit5</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.arcmutate</groupId>
<groupId>com.groupcdg</groupId>
<artifactId>pitest-git-plugin</artifactId>
<version>${version.pitest-git}</version>
</dependency>
<dependency>
<groupId>com.groupcdg.arcmutate</groupId>
<artifactId>base</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>com.groupcdg.pitest</groupId>
<artifactId>pitest-accelerator-junit5</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>1.2.2</version>
<version>1.2.1</version>
</dependency>
</dependencies>
<executions>
@@ -1591,7 +1578,7 @@
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.1.0.4751</version>
<version>5.0.0.4389</version>
</plugin>
</plugins>
</pluginManagement>
@@ -1950,9 +1937,10 @@
-XepOpt:NullAway:AnnotatedPackages=tech.picnic
-XepOpt:NullAway:AssertsEnabled=true
-XepOpt:NullAway:CheckOptionalEmptiness=true
-XepOpt:NullAway:JSpecifyMode=true
-XepOpt:Nullness:Conservative=false
-XepOpt:StatementSwitchToExpressionSwitch:EnableAssignmentSwitchConversion=true
-XepOpt:StatementSwitchToExpressionSwitch:EnableDirectConversion=true
-XepOpt:StatementSwitchToExpressionSwitch:EnableReturnSwitchConversion=true
<!-- Append additional custom arguments. -->
${error-prone.patch-args}
${error-prone.self-check-args}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>refaster-compiler</artifactId>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>refaster-runner</artifactId>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>refaster-support</artifactId>
@@ -15,6 +15,10 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>error-prone-utils</artifactId>
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>

View File

@@ -10,18 +10,24 @@ import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
import static tech.picnic.errorprone.utils.MoreTypePredicates.isSubTypeOf;
import static tech.picnic.errorprone.utils.MoreTypes.generic;
import static tech.picnic.errorprone.utils.MoreTypes.type;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.errorprone.VisitorState;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -57,6 +63,7 @@ import java.util.stream.Stream;
public final class IsEmpty implements Matcher<ExpressionTree> {
private static final long serialVersionUID = 1L;
private static final Integer ZERO = 0;
private static final Supplier<Type> VOID = type(Void.class.getCanonicalName());
private static final Pattern EMPTY_INSTANCE_FACTORY_METHOD_PATTERN = Pattern.compile("empty.*");
private static final Matcher<Tree> EMPTY_COLLECTION_CONSTRUCTOR_ARGUMENT =
anyOf(isPrimitiveType(), isSubtypeOf(Comparator.class));
@@ -73,7 +80,7 @@ public final class IsEmpty implements Matcher<ExpressionTree> {
isSameType(TreeMap.class),
isSameType(TreeSet.class),
isSameType(Vector.class));
private static final Matcher<ExpressionTree> EMPTY_INSTANCE_FACTORY =
private static final Matcher<ExpressionTree> EMPTY_INSTANCE =
anyOf(
staticField(Collections.class.getCanonicalName(), "EMPTY_LIST"),
staticField(Collections.class.getCanonicalName(), "EMPTY_MAP"),
@@ -103,9 +110,10 @@ public final class IsEmpty implements Matcher<ExpressionTree> {
"reactor.core.publisher.Mono",
"reactor.util.context.Context")
.named("empty"),
staticMethod()
.onDescendantOf("reactor.core.publisher.Flux")
.named("just")))));
staticMethod().onDescendantOf("reactor.core.publisher.Flux").named("just")))),
// XXX: We could also match `Iterable<Void>` and `Stream<Void>` subtypes, but those are
// rarely or never seen in the wild.
typePredicateMatcher(isSubTypeOf(generic(type("org.reactivestreams.Publisher"), VOID))));
/** Instantiates a new {@link IsEmpty} instance. */
public IsEmpty() {}
@@ -113,17 +121,16 @@ public final class IsEmpty implements Matcher<ExpressionTree> {
@Override
public boolean matches(ExpressionTree tree, VisitorState state) {
return isEmptyArrayCreation(tree)
|| EMPTY_INSTANCE_FACTORY.matches(tree, state)
|| EMPTY_INSTANCE.matches(tree, state)
|| isEmptyCollectionConstructor(tree, state);
}
private boolean isEmptyCollectionConstructor(ExpressionTree tree, VisitorState state) {
if (!(tree instanceof NewClassTree newClassTree)
|| !MUTABLE_COLLECTION_TYPE.matches(tree, state)) {
if (!(tree instanceof NewClassTree) || !MUTABLE_COLLECTION_TYPE.matches(tree, state)) {
return false;
}
List<? extends ExpressionTree> arguments = newClassTree.getArguments();
List<? extends ExpressionTree> arguments = ((NewClassTree) tree).getArguments();
if (arguments.stream().allMatch(a -> EMPTY_COLLECTION_CONSTRUCTOR_ARGUMENT.matches(a, state))) {
/*
* This is a default constructor, or a constructor that creates an empty collection using

View File

@@ -429,6 +429,11 @@ final class IsEmptyTest {
" // BUG: Diagnostic contains:",
" return Flux.just();",
" }",
"",
" Mono<Void> positive57() {",
" // BUG: Diagnostic contains:",
" return Mono.just(1).then();",
" }",
"}")
.doTest();
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.22.1-SNAPSHOT</version>
<version>0.20.1-SNAPSHOT</version>
</parent>
<artifactId>refaster-test-support</artifactId>

View File

@@ -6,7 +6,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.naturalOrder;
import static tech.picnic.errorprone.refaster.runner.Refaster.INCLUDED_RULES_PATTERN_FLAG;
@@ -18,7 +17,6 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;
import com.google.common.io.Resources;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.BugPattern;
@@ -40,9 +38,6 @@ import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Position;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -129,15 +124,13 @@ public final class RefasterRuleCollection extends BugChecker implements Compilat
*/
public static void validate(Class<?> clazz) {
String className = clazz.getSimpleName();
String inputResource = className + "TestInput.java";
String outputResource = className + "TestOutput.java";
BugCheckerRefactoringTestHelper.newInstance(RefasterRuleCollection.class, clazz)
.setArgs(
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
"-XepOpt:" + RULE_COLLECTION_FLAG + '=' + className)
.addInputLines(inputResource, loadResource(clazz, inputResource))
.addOutputLines(outputResource, loadResource(clazz, outputResource))
.addInput(className + "TestInput.java")
.addOutput(className + "TestOutput.java")
.doTest(TestMode.TEXT_MATCH);
}
@@ -254,15 +247,6 @@ public final class RefasterRuleCollection extends BugChecker implements Compilat
return value.substring(index + 1);
}
private static String loadResource(Class<?> contextClass, String resource) {
URL url = Resources.getResource(contextClass, resource);
try {
return Resources.toString(url, UTF_8);
} catch (IOException e) {
throw new UncheckedIOException("Cannot find resource: " + url, e);
}
}
private class UnexpectedMatchReporter extends TreeScanner<@Nullable Void, VisitorState> {
private final ImmutableRangeMap<Integer, String> indexedMatches;

View File

@@ -1,12 +1,6 @@
# An overview of Error Prone Support releases, along with compatible Error
# Prone releases. This data was generated by `generate-version-compatibility-overview.sh`.
releases:
- version: 0.22.0
compatible:
- "2.37.0"
- version: 0.21.0
compatible:
- "2.37.0"
- version: 0.20.0
compatible:
- "2.36.0"