mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
33 Commits
sschroever
...
rossendrij
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4974f5afb4 | ||
|
|
00012c6aa8 | ||
|
|
193589d193 | ||
|
|
1a1588d413 | ||
|
|
6656bd8186 | ||
|
|
26a9b46de7 | ||
|
|
17e74f778b | ||
|
|
e1bdb098de | ||
|
|
0be162c837 | ||
|
|
edfb2a70e8 | ||
|
|
c1e5dc4339 | ||
|
|
7218006b3c | ||
|
|
a3f599ba1b | ||
|
|
f819a3e42f | ||
|
|
7fc865c769 | ||
|
|
0287060d96 | ||
|
|
ac4e81f2c7 | ||
|
|
350f028781 | ||
|
|
299ce7b800 | ||
|
|
f3a929a3bb | ||
|
|
625a55add5 | ||
|
|
ef59340987 | ||
|
|
f2aea38b17 | ||
|
|
5cd8863eb5 | ||
|
|
5b57b4720b | ||
|
|
5224571407 | ||
|
|
c8189e9431 | ||
|
|
0fe42f1ea6 | ||
|
|
78b29107a3 | ||
|
|
7ae7d5105a | ||
|
|
0976b33d61 | ||
|
|
4b6f81c4fa | ||
|
|
1e879c175e |
10
.mvn/jvm.config
Normal file
10
.mvn/jvm.config
Normal file
@@ -0,0 +1,10 @@
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||
--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
|
||||
--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
|
||||
@@ -171,10 +171,25 @@
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
|
||||
@@ -17,9 +17,11 @@ import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import java.util.Optional;
|
||||
|
||||
/** A {@link BugChecker} which flags empty methods that seemingly can simply be deleted. */
|
||||
@AutoService(BugChecker.class)
|
||||
@@ -41,7 +43,8 @@ public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatc
|
||||
if (tree.getBody() == null
|
||||
|| !tree.getBody().getStatements().isEmpty()
|
||||
|| ASTHelpers.containsComments(tree, state)
|
||||
|| PERMITTED_ANNOTATION.matches(tree, state)) {
|
||||
|| PERMITTED_ANNOTATION.matches(tree, state)
|
||||
|| isInPossibleTestHelperClass(state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@@ -52,4 +55,11 @@ public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatc
|
||||
|
||||
return describeMatch(tree, SuggestedFix.delete(tree));
|
||||
}
|
||||
|
||||
private static boolean isInPossibleTestHelperClass(VisitorState state) {
|
||||
return Optional.ofNullable(ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class))
|
||||
.map(ClassTree::getSimpleName)
|
||||
.filter(name -> name.toString().contains("Test"))
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.anyMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.LinkType;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.BugPattern.StandardTags;
|
||||
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.util.ASTHelpers;
|
||||
import com.sun.source.tree.BinaryTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.ParenthesizedTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.util.SimpleTreeVisitor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags string concatenations that produce a format string; in such
|
||||
* cases the string concatenation should instead be deferred to the invoked method.
|
||||
*
|
||||
* @implNote This checker is based on the implementation of {@link
|
||||
* com.google.errorprone.bugpatterns.flogger.FloggerStringConcatenation}.
|
||||
*/
|
||||
// XXX: Support arbitrary `@FormatMethod`-annotated methods.
|
||||
// XXX: For (explicit or delegated) invocations of `java.util.Formatter` _strictly speaking_ we
|
||||
// should introduce special handling of `Formattable` arguments, as this check would replace a
|
||||
// `Formattable#toString` invocation with a `Formattable#formatTo` invocation. But likely that
|
||||
// should be considered a bug fix, too.
|
||||
// XXX: Introduce a separate check which adds/removes the `Locale` parameter to `String.format`
|
||||
// invocations, as necessary.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "FormatStringConcatenation",
|
||||
summary = "Defer string concatenation to the invoked method",
|
||||
linkType = LinkType.NONE,
|
||||
severity = SeverityLevel.WARNING,
|
||||
tags = StandardTags.SIMPLIFICATION)
|
||||
public final class FormatStringConcatenationCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* AssertJ exposes varargs {@code fail} methods with a {@link Throwable}-accepting overload, the
|
||||
* latter of which should not be flagged.
|
||||
*/
|
||||
private static final Matcher<ExpressionTree> ASSERTJ_FAIL_WITH_THROWABLE_METHOD =
|
||||
anyMethod()
|
||||
.anyClass()
|
||||
.withAnyName()
|
||||
.withParameters(String.class.getName(), Throwable.class.getName());
|
||||
// XXX: Drop some of these methods if we use Refaster to replace some with others.
|
||||
private static final Matcher<ExpressionTree> ASSERTJ_FORMAT_METHOD =
|
||||
anyOf(
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.assertj.core.api.AbstractAssert")
|
||||
.namedAnyOf("overridingErrorMessage", "withFailMessage"),
|
||||
allOf(
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.assertj.core.api.AbstractSoftAssertions")
|
||||
.named("fail"),
|
||||
not(ASSERTJ_FAIL_WITH_THROWABLE_METHOD)),
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.assertj.core.api.AbstractStringAssert")
|
||||
.named("isEqualTo"),
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.assertj.core.api.AbstractThrowableAssert")
|
||||
.namedAnyOf(
|
||||
"hasMessage",
|
||||
"hasMessageContaining",
|
||||
"hasMessageEndingWith",
|
||||
"hasMessageStartingWith",
|
||||
"hasRootCauseMessage",
|
||||
"hasStackTraceContaining"),
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.assertj.core.api.Descriptable")
|
||||
.namedAnyOf("as", "describedAs"),
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.assertj.core.api.ThrowableAssertAlternative")
|
||||
.namedAnyOf(
|
||||
"withMessage",
|
||||
"withMessageContaining",
|
||||
"withMessageEndingWith",
|
||||
"withMessageStartingWith",
|
||||
"withStackTraceContaining"),
|
||||
allOf(
|
||||
instanceMethod().onDescendantOf("org.assertj.core.api.WithAssertions").named("fail"),
|
||||
not(ASSERTJ_FAIL_WITH_THROWABLE_METHOD)),
|
||||
allOf(
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
"org.assertj.core.api.Assertions",
|
||||
"org.assertj.core.api.BDDAssertions",
|
||||
"org.assertj.core.api.Fail")
|
||||
.named("fail"),
|
||||
not(ASSERTJ_FAIL_WITH_THROWABLE_METHOD)));
|
||||
private static final Matcher<ExpressionTree> GUAVA_FORMAT_METHOD =
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onClass("com.google.common.base.Preconditions")
|
||||
.namedAnyOf("checkArgument", "checkNotNull", "checkState"),
|
||||
staticMethod().onClass("com.google.common.base.Verify").named("verify"));
|
||||
// XXX: Add `PrintWriter`, maybe others.
|
||||
private static final Matcher<ExpressionTree> JDK_FORMAT_METHOD =
|
||||
anyOf(
|
||||
staticMethod().onClass("java.lang.String").named("format"),
|
||||
instanceMethod().onExactClass("java.util.Formatter").named("format"));
|
||||
private static final Matcher<ExpressionTree> SLF4J_FORMAT_METHOD =
|
||||
instanceMethod()
|
||||
.onDescendantOf("org.slf4j.Logger")
|
||||
.namedAnyOf("debug", "error", "info", "trace", "warn");
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (hasNonConstantStringConcatenationArgument(tree, 0, state)) {
|
||||
return flagViolation(tree, ASSERTJ_FORMAT_METHOD, 0, "%s", state)
|
||||
.or(() -> flagViolation(tree, JDK_FORMAT_METHOD, 0, "%s", state))
|
||||
.or(() -> flagViolation(tree, SLF4J_FORMAT_METHOD, 0, "{}", state))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
if (hasNonConstantStringConcatenationArgument(tree, 1, state)) {
|
||||
return flagViolation(tree, GUAVA_FORMAT_METHOD, 1, "%s", state)
|
||||
.or(() -> flagViolation(tree, JDK_FORMAT_METHOD, 1, "%s", state))
|
||||
.or(() -> flagViolation(tree, SLF4J_FORMAT_METHOD, 1, "{}", state))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags the given method invocation if it matches a targeted method and passes a non-compile time
|
||||
* constant string concatenation as a format string.
|
||||
*/
|
||||
private Optional<Description> flagViolation(
|
||||
MethodInvocationTree tree,
|
||||
Matcher<ExpressionTree> matcher,
|
||||
int formatStringParam,
|
||||
String formatSpecifier,
|
||||
VisitorState state) {
|
||||
if (!matcher.matches(tree, state)) {
|
||||
/* The invoked method is not targeted by this check. */
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<? extends ExpressionTree> arguments = tree.getArguments();
|
||||
|
||||
if (arguments.size() > formatStringParam + 1) {
|
||||
/*
|
||||
* This method invocation uses explicit string concatenation but _also_ already relies on
|
||||
* format specifiers: flag but don't suggest a fix.
|
||||
*/
|
||||
return Optional.of(describeMatch(tree));
|
||||
}
|
||||
|
||||
ExpressionTree formatStringArg = arguments.get(formatStringParam);
|
||||
ReplacementArgumentsConstructor replacementConstructor =
|
||||
new ReplacementArgumentsConstructor(formatSpecifier);
|
||||
formatStringArg.accept(replacementConstructor, state);
|
||||
|
||||
return Optional.of(
|
||||
describeMatch(
|
||||
tree,
|
||||
SuggestedFix.replace(
|
||||
formatStringArg, replacementConstructor.getReplacementArguments(state))));
|
||||
}
|
||||
|
||||
private static boolean hasNonConstantStringConcatenationArgument(
|
||||
MethodInvocationTree tree, int argPosition, VisitorState state) {
|
||||
List<? extends ExpressionTree> arguments = tree.getArguments();
|
||||
if (arguments.size() <= argPosition) {
|
||||
/* This method doesn't accept enough parameters. */
|
||||
return false;
|
||||
}
|
||||
|
||||
ExpressionTree argument = ASTHelpers.stripParentheses(arguments.get(argPosition));
|
||||
return argument instanceof BinaryTree
|
||||
&& isStringTyped(argument, state)
|
||||
&& ASTHelpers.constValue(argument, String.class) == null;
|
||||
}
|
||||
|
||||
private static boolean isStringTyped(ExpressionTree tree, VisitorState state) {
|
||||
return ASTHelpers.isSameType(ASTHelpers.getType(tree), state.getSymtab().stringType, state);
|
||||
}
|
||||
|
||||
private static class ReplacementArgumentsConstructor
|
||||
extends SimpleTreeVisitor<Void, VisitorState> {
|
||||
private final StringBuilder formatString = new StringBuilder();
|
||||
private final List<Tree> formatArguments = new ArrayList<>();
|
||||
private final String formatSpecifier;
|
||||
|
||||
ReplacementArgumentsConstructor(String formatSpecifier) {
|
||||
this.formatSpecifier = formatSpecifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitBinary(BinaryTree tree, VisitorState state) {
|
||||
if (tree.getKind() == Kind.PLUS && isStringTyped(tree, state)) {
|
||||
tree.getLeftOperand().accept(this, state);
|
||||
tree.getRightOperand().accept(this, state);
|
||||
} else {
|
||||
appendExpression(tree);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitParenthesized(ParenthesizedTree tree, VisitorState state) {
|
||||
return tree.getExpression().accept(this, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void defaultAction(Tree tree, VisitorState state) {
|
||||
appendExpression(tree);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void appendExpression(Tree tree) {
|
||||
if (tree instanceof LiteralTree) {
|
||||
formatString.append(((LiteralTree) tree).getValue());
|
||||
} else {
|
||||
formatString.append(formatSpecifier);
|
||||
formatArguments.add(tree);
|
||||
}
|
||||
}
|
||||
|
||||
private String getReplacementArguments(VisitorState state) {
|
||||
return state.getConstantExpression(formatString.toString())
|
||||
+ ", "
|
||||
+ formatArguments.stream()
|
||||
.map(tree -> Util.treeToString(tree, state))
|
||||
.collect(joining(", "));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
@@ -22,6 +23,7 @@ import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
@@ -59,6 +61,13 @@ public final class JUnitMethodDeclarationCheck extends BugChecker implements Met
|
||||
isType("org.junit.jupiter.api.AfterEach"),
|
||||
isType("org.junit.jupiter.api.BeforeAll"),
|
||||
isType("org.junit.jupiter.api.BeforeEach")));
|
||||
private static final ImmutableMap<String, String> REPLACEMENTS =
|
||||
ImmutableMap.<String, String>builder()
|
||||
.put("org.junit.jupiter.api.AfterAll", "afterAll")
|
||||
.put("org.junit.jupiter.api.AfterEach", "tearDown")
|
||||
.put("org.junit.jupiter.api.BeforeAll", "beforeAll")
|
||||
.put("org.junit.jupiter.api.BeforeEach", "setUp")
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
@@ -83,9 +92,32 @@ public final class JUnitMethodDeclarationCheck extends BugChecker implements Met
|
||||
tryCanonicalizeMethodName(tree, state).ifPresent(builder::merge);
|
||||
}
|
||||
|
||||
if (SETUP_OR_TEARDOWN_METHOD.matches(tree, state)) {
|
||||
tryCanonicalizeSetupOrTeardownMethod(tree, state).ifPresent(builder::merge);
|
||||
}
|
||||
|
||||
return builder.isEmpty() ? Description.NO_MATCH : describeMatch(tree, builder.build());
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> tryCanonicalizeSetupOrTeardownMethod(
|
||||
MethodTree tree, VisitorState state) {
|
||||
Symbol.MethodSymbol symbol = ASTHelpers.getSymbol(tree);
|
||||
|
||||
return symbol.getAnnotationMirrors().stream()
|
||||
.map(compound -> compound.getAnnotationType().toString())
|
||||
.filter(REPLACEMENTS::containsKey)
|
||||
.filter(
|
||||
e ->
|
||||
!symbol
|
||||
.getSimpleName()
|
||||
.toString()
|
||||
.startsWith(
|
||||
Objects.requireNonNull(
|
||||
REPLACEMENTS.get(e)))) // , tree.getName().toString()))
|
||||
.findFirst()
|
||||
.map(e -> SuggestedFixes.renameMethod(tree, REPLACEMENTS.get(e), state));
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> tryCanonicalizeMethodName(
|
||||
MethodTree tree, VisitorState state) {
|
||||
return Optional.ofNullable(ASTHelpers.getSymbol(tree))
|
||||
|
||||
@@ -69,7 +69,10 @@ public final class MethodReferenceUsageCheck extends BugChecker
|
||||
*/
|
||||
return constructMethodRef(tree, tree.getBody())
|
||||
.map(SuggestedFix.Builder::build)
|
||||
.filter(fix -> SuggestedFixes.compilesWithFix(fix, state))
|
||||
.filter(
|
||||
fix ->
|
||||
SuggestedFixes.compilesWithFix(
|
||||
fix, state, ImmutableList.of(), /* onlyInSameCompilationUnit= */ true))
|
||||
.map(fix -> describeMatch(tree, fix))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.LinkType;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.BugPattern.StandardTags;
|
||||
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.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags method invocations for which all arguments are wrapped using
|
||||
* {@link org.mockito.Mockito#eq}; this is redundant.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "MockitoStubbing",
|
||||
summary = "Don't unnecessarily use Mockito's `eq(...)`",
|
||||
linkType = LinkType.NONE,
|
||||
severity = SeverityLevel.SUGGESTION,
|
||||
tags = StandardTags.SIMPLIFICATION)
|
||||
public final class MockitoStubbingCheck extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MOCKITO_EQ_METHOD =
|
||||
staticMethod().onClass("org.mockito.ArgumentMatchers").named("eq");
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
List<? extends ExpressionTree> arguments = tree.getArguments();
|
||||
if (arguments.isEmpty() || !arguments.stream().allMatch(arg -> isEqInvocation(arg, state))) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
SuggestedFix.Builder suggestedFix = SuggestedFix.builder();
|
||||
for (ExpressionTree arg : arguments) {
|
||||
suggestedFix.replace(
|
||||
arg,
|
||||
Util.treeToString(
|
||||
Iterables.getOnlyElement(((MethodInvocationTree) arg).getArguments()), state));
|
||||
}
|
||||
|
||||
return describeMatch(tree, suggestedFix.build());
|
||||
}
|
||||
|
||||
private static boolean isEqInvocation(ExpressionTree tree, VisitorState state) {
|
||||
return tree instanceof MethodInvocationTree && MOCKITO_EQ_METHOD.matches(tree, state);
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,8 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
|
||||
// XXX: This `try/catch` block handles the issue described and resolved in
|
||||
// https://github.com/google/error-prone/pull/2456. Drop this block once that change is
|
||||
// released.
|
||||
// XXX: Find a way to identify that we're running Picnic's Error Prone fork and disable this
|
||||
// fallback if so, as it might hide other bugs.
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
/* Then apply them. */
|
||||
|
||||
@@ -80,6 +80,7 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
|
||||
"org.mockito.Answers",
|
||||
"org.mockito.ArgumentMatchers",
|
||||
"org.mockito.Mockito",
|
||||
"org.springframework.boot.test.context.SpringBootTest.WebEnvironment",
|
||||
"org.springframework.format.annotation.DateTimeFormat.ISO",
|
||||
"org.springframework.http.HttpHeaders",
|
||||
"org.springframework.http.HttpMethod",
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.enclosingClass;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
@@ -35,7 +39,11 @@ public final class TimeZoneUsageCheck extends BugChecker implements MethodInvoca
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> BANNED_TIME_METHOD =
|
||||
anyOf(
|
||||
instanceMethod().onDescendantOf(Clock.class.getName()).namedAnyOf("getZone", "withZone"),
|
||||
allOf(
|
||||
instanceMethod()
|
||||
.onDescendantOf(Clock.class.getName())
|
||||
.namedAnyOf("getZone", "withZone"),
|
||||
not(enclosingClass(isSubtypeOf(Clock.class)))),
|
||||
staticMethod()
|
||||
.onClass(Clock.class.getName())
|
||||
.namedAnyOf(
|
||||
|
||||
@@ -97,12 +97,24 @@ final class AssertJOptionalTemplates {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
|
||||
AbstractOptionalAssert<?, T> after(AbstractOptionalAssert<?, T> optionalAssert, T value) {
|
||||
return optionalAssert.hasValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AbstractOptionalAssertContainsSame<T> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(AbstractOptionalAssert<?, T> optionalAssert, T value) {
|
||||
return Refaster.anyOf(
|
||||
optionalAssert.get().isSameAs(value), optionalAssert.isPresent().isSameAs(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
AbstractOptionalAssert<?, T> after(AbstractOptionalAssert<?, T> optionalAssert, T value) {
|
||||
return optionalAssert.containsSame(value);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatOptionalHasValueMatching<T> {
|
||||
@BeforeTemplate
|
||||
AbstractOptionalAssert<?, T> before(Optional<T> optional, Predicate<? super T> predicate) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.util.stream.Collector;
|
||||
import java.util.stream.Stream;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractCollectionAssert;
|
||||
import org.assertj.core.api.AbstractComparableAssert;
|
||||
import org.assertj.core.api.AbstractDoubleAssert;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
@@ -357,6 +358,18 @@ final class AssertJTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatSetContainsExactlyOneElement<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(Set<S> set, T element) {
|
||||
return assertThat(set).containsOnly(element);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ObjectEnumerableAssert<?, S> after(Set<S> set, T element) {
|
||||
return assertThat(set).containsExactly(element);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsOneDistinctElement<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
@@ -517,7 +530,7 @@ final class AssertJTemplates {
|
||||
|
||||
static final class AssertThatSetsAreEqual<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
IterableAssert<S> before(Set<S> set1, Set<T> set2) {
|
||||
AbstractCollectionAssert<?, ?, S, ?> before(Set<S> set1, Set<T> set2) {
|
||||
return Refaster.anyOf(
|
||||
assertThat(set1).isEqualTo(set2),
|
||||
assertThat(set1).containsExactlyInAnyOrderElementsOf(set2));
|
||||
@@ -525,7 +538,7 @@ final class AssertJTemplates {
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
|
||||
IterableAssert<S> after(Set<S> set1, Set<T> set2) {
|
||||
AbstractCollectionAssert<?, ?, S, ?> after(Set<S> set1, Set<T> set2) {
|
||||
return assertThat(set1).hasSameElementsAs(set2);
|
||||
}
|
||||
}
|
||||
@@ -536,13 +549,13 @@ final class AssertJTemplates {
|
||||
|
||||
static final class AssertThatMultisetsAreEqual<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
IterableAssert<S> before(Multiset<S> multiset1, Multiset<T> multiset2) {
|
||||
AbstractCollectionAssert<?, ?, S, ?> before(Multiset<S> multiset1, Multiset<T> multiset2) {
|
||||
return assertThat(multiset1).isEqualTo(multiset2);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
|
||||
IterableAssert<S> after(Multiset<S> multiset1, Multiset<T> multiset2) {
|
||||
AbstractCollectionAssert<?, ?, S, ?> after(Multiset<S> multiset1, Multiset<T> multiset2) {
|
||||
return assertThat(multiset1).containsExactlyInAnyOrderElementsOf(multiset2);
|
||||
}
|
||||
}
|
||||
@@ -922,7 +935,7 @@ final class AssertJTemplates {
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
IterableAssert<T> before2(
|
||||
AbstractCollectionAssert<?, ?, T, ?> before2(
|
||||
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, Iterable<U> iterable) {
|
||||
return assertThat(stream.collect(collector)).containsExactlyInAnyOrderElementsOf(iterable);
|
||||
}
|
||||
@@ -943,7 +956,7 @@ final class AssertJTemplates {
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
IterableAssert<T> before2(
|
||||
AbstractCollectionAssert<?, ?, T, ?> before2(
|
||||
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, U[] array) {
|
||||
return assertThat(stream.collect(collector)).containsExactlyInAnyOrder(array);
|
||||
}
|
||||
@@ -967,7 +980,7 @@ final class AssertJTemplates {
|
||||
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatStreamContainsExactlyInAnyOrder" /* Varargs converted to array. */)
|
||||
IterableAssert<T> before2(
|
||||
AbstractCollectionAssert<?, ?, T, ?> before2(
|
||||
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, @Repeated U elements) {
|
||||
return assertThat(stream.collect(collector))
|
||||
.containsExactlyInAnyOrder(Refaster.asVarargs(elements));
|
||||
|
||||
@@ -128,19 +128,6 @@ final class ImmutableListTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't call {@link ImmutableList#asList()}; it is a no-op. */
|
||||
static final class ImmutableListAsList<T> {
|
||||
@BeforeTemplate
|
||||
ImmutableList<T> before(ImmutableList<T> list) {
|
||||
return list.asList();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableList<T> after(ImmutableList<T> list) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link ImmutableList#sortedCopyOf(Iterable)} over more contrived alternatives. */
|
||||
static final class ImmutableListSortedCopyOf<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Refaster templates related to expressions dealing with {@link Optional}s. */
|
||||
final class OptionalTemplates {
|
||||
@@ -24,7 +25,7 @@ final class OptionalTemplates {
|
||||
// parentheses around the null check, but that's currently not the case. Try to fix that.
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("TernaryOperatorOptionalNegativeFiltering" /* Special case. */)
|
||||
Optional<T> before(T object) {
|
||||
Optional<T> before(@Nullable T object) {
|
||||
return object == null ? Optional.empty() : Optional.of(object);
|
||||
}
|
||||
|
||||
@@ -91,19 +92,6 @@ final class OptionalTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#stream()} over the Guava alternative. */
|
||||
static final class OptionalToStream<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Optional<T> optional) {
|
||||
return Streams.stream(optional);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<T> after(Optional<T> optional) {
|
||||
return optional.stream();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use the ternary operator to extract the first element of a possibly-empty {@link
|
||||
* Iterator} as an {@link Optional}.
|
||||
|
||||
@@ -161,6 +161,32 @@ final class ReactorTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#flux()}} over more contrived alternatives. */
|
||||
static final class MonoFlux<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Mono<T> mono) {
|
||||
return Flux.concat(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Mono<T> mono) {
|
||||
return mono.flux();
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily invoke {@link Flux#concat(Publisher)}. */
|
||||
static final class FluxIdentity<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux) {
|
||||
return Flux.concat(flux);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux) {
|
||||
return flux;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer a collection using {@link MoreCollectors#toOptional()} over more contrived alternatives.
|
||||
*/
|
||||
@@ -194,6 +220,32 @@ final class ReactorTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#as(Function)} when creating a {@link StepVerifier}. */
|
||||
static final class StepVerifierFromMono<T> {
|
||||
@BeforeTemplate
|
||||
StepVerifier.FirstStep<? extends T> before(Mono<T> mono) {
|
||||
return StepVerifier.create(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
StepVerifier.FirstStep<? extends T> after(Mono<T> mono) {
|
||||
return mono.as(StepVerifier::create);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#as(Function)} when creating a {@link StepVerifier}. */
|
||||
static final class StepVerifierFromFlux<T> {
|
||||
@BeforeTemplate
|
||||
StepVerifier.FirstStep<? extends T> before(Flux<T> flux) {
|
||||
return StepVerifier.create(flux);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
StepVerifier.FirstStep<? extends T> after(Flux<T> flux) {
|
||||
return flux.as(StepVerifier::create);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily call {@link StepVerifier.Step#expectNext(Object[])}. */
|
||||
static final class StepVerifierStepExpectNextEmpty<T> {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -148,6 +148,8 @@ final class StreamTemplates {
|
||||
*/
|
||||
// XXX: Consider whether to have a similar rule for `.findAny()`. For parallel streams it
|
||||
// wouldn't be quite the same....
|
||||
// XXX: This change is not equivalent for `null`-returning functions, as the original code throws
|
||||
// an NPE if the first element is `null`, while the latter yields an empty `Optional`.
|
||||
static final class StreamMapFirst<T, S> {
|
||||
@BeforeTemplate
|
||||
Optional<S> before(Stream<T> stream, Function<? super T, S> function) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Refaster templates related to expressions dealing with {@link String}s. */
|
||||
// XXX: Should we prefer `s -> !s.isEmpty()` or `not(String::isEmpty)`?
|
||||
@@ -37,7 +38,7 @@ final class StringTemplates {
|
||||
/** Prefer {@link Strings#isNullOrEmpty(String)} over the more verbose alternative. */
|
||||
static final class StringIsNullOrEmpty {
|
||||
@BeforeTemplate
|
||||
boolean before(String str) {
|
||||
boolean before(@Nullable String str) {
|
||||
return str == null || str.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package tech.picnic.errorprone.refastertemplates;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
|
||||
|
||||
/**
|
||||
* Refaster templates related to expressions dealing with {@link
|
||||
* org.springframework.web.reactive.function.client.WebClient} and related types.
|
||||
*/
|
||||
final class WebClientTemplates {
|
||||
private WebClientTemplates() {}
|
||||
|
||||
/** Prefer {@link RequestBodySpec#bodyValue(Object)} over more contrived alternatives. */
|
||||
static final class BodyValue<T> {
|
||||
@BeforeTemplate
|
||||
RequestHeadersSpec<?> before(RequestBodySpec requestBodySpec, T value) {
|
||||
return requestBodySpec.body(fromValue(value));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
WebTestClient.RequestHeadersSpec<?> before2(
|
||||
WebTestClient.RequestBodySpec requestBodySpec, T value) {
|
||||
return requestBodySpec.body(fromValue(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
RequestHeadersSpec<?> after(RequestBodySpec requestBodySpec, T value) {
|
||||
return requestBodySpec.bodyValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,10 @@ public final class EmptyMethodCheckTest {
|
||||
" interface F {",
|
||||
" void fun();",
|
||||
" }",
|
||||
"",
|
||||
" final class MyTestClass {",
|
||||
" void helperMethod() {}",
|
||||
" }",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
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;
|
||||
|
||||
public final class FormatStringConcatenationCheckTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(FormatStringConcatenationCheck.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenationCheck.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static com.google.common.base.Preconditions.checkNotNull;",
|
||||
"import static com.google.common.base.Preconditions.checkState;",
|
||||
"import static com.google.common.base.Verify.verify;",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"import static org.assertj.core.api.SoftAssertions.assertSoftly;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Formatter;",
|
||||
"import org.assertj.core.api.Assertions;",
|
||||
"import org.assertj.core.api.BDDAssertions;",
|
||||
"import org.assertj.core.api.Fail;",
|
||||
"import org.assertj.core.api.ThrowableAssertAlternative;",
|
||||
"import org.assertj.core.api.WithAssertions;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" void negative() {",
|
||||
" hashCode();",
|
||||
" equals(new A());",
|
||||
" equals(toString());",
|
||||
" equals(0);",
|
||||
" equals(\"str\");",
|
||||
" equals(\"str\" + 0);",
|
||||
" equals(0 + 0);",
|
||||
" equals(0 - 0);",
|
||||
" equals(\"str \" + toString());",
|
||||
" }",
|
||||
"",
|
||||
" void assertj() {",
|
||||
" assertThat(0).overridingErrorMessage(toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str\");",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + 0);",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s\", 2 * 3);",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage((\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).withFailMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).withFailMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertSoftly(softly -> softly.fail(\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertSoftly(softly -> softly.fail(\"%s \" + toString(), \"arg\"));",
|
||||
" assertSoftly(softly -> softly.fail(\"str \" + toString(), new Throwable()));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(\"\").isEqualTo(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(\"\").isEqualTo(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageEndingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageEndingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageStartingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageStartingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasRootCauseMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasRootCauseMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasStackTraceContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasStackTraceContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).as(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).as(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).describedAs(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).describedAs(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageEndingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageEndingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageStartingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageStartingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withStackTraceContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withStackTraceContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((WithAssertions) null).fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((WithAssertions) null).fail(\"%s \" + toString(), \"arg\");",
|
||||
" ((WithAssertions) null).fail(\"str \" + toString(), new Throwable());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Assertions.fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Assertions.fail(\"%s \" + toString(), \"arg\");",
|
||||
" Assertions.fail(\"str \" + toString(), new Throwable());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" BDDAssertions.fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" BDDAssertions.fail(\"%s \" + toString(), \"arg\");",
|
||||
" BDDAssertions.fail(\"str \" + toString(), new Throwable());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Fail.fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Fail.fail(\"%s \" + toString(), \"arg\");",
|
||||
" Fail.fail(\"str \" + toString(), new Throwable());",
|
||||
" }",
|
||||
"",
|
||||
" void guava() {",
|
||||
" checkArgument(true);",
|
||||
" checkArgument(true, toString());",
|
||||
" checkArgument(true, \"str\");",
|
||||
" checkArgument(true, \"str \" + 0);",
|
||||
" checkArgument(true, \"str %s\", 2 * 3);",
|
||||
" checkArgument(true, \"str %s\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, \"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, (\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, \"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkNotNull(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkNotNull(true, \"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkState(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkState(true, \"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verify(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verify(true, \"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void jdk() {",
|
||||
" String.format(\"str\");",
|
||||
" String.format(\"str \" + 0);",
|
||||
" String.format(\"str {}\", 2 * 3);",
|
||||
" String.format(\"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(\"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format((\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" String.format(Locale.ROOT, \"str\");",
|
||||
" String.format(Locale.ROOT, \"str \" + 0);",
|
||||
" String.format(Locale.ROOT, \"str {}\", 2 * 3);",
|
||||
" String.format(Locale.ROOT, \"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(Locale.ROOT, (\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(Locale.ROOT, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(Locale.ROOT, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void slf4j() {",
|
||||
" LOG.debug(\"str\");",
|
||||
" LOG.debug(\"str \" + 0);",
|
||||
" LOG.debug(\"str {}\", 2 * 3);",
|
||||
" LOG.debug(\"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(\"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" LOG.debug((Marker) null, \"str\");",
|
||||
" LOG.debug((Marker) null, \"str \" + 0);",
|
||||
" LOG.debug((Marker) null, \"str {}\", 2 * 3);",
|
||||
" LOG.debug((Marker) null, \"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((Marker) null, (\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((Marker) null, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error((Marker) null,\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error((Marker) null,\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info((Marker) null,\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info((Marker) null,\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace((Marker) null,\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace((Marker) null,\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn((Marker) null,\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn((Marker) null,\"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"in/A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Formatter;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" void assertj() {",
|
||||
" assertThat(0).overridingErrorMessage(toString() + \" str\");",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + toString());",
|
||||
" assertThat(0).overridingErrorMessage(toString() + toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + toString() + \" word \" + new A().hashCode());",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + (toString() + \" word \") + (hashCode() / 2));",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void guava() {",
|
||||
" checkArgument(true, \"str \" + toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" checkArgument(true, \"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void jdk() {",
|
||||
" String.format(\"str \" + toString());",
|
||||
" String.format(Locale.ROOT, \"str \" + toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" String.format(\"{} \" + toString(), \"arg\");",
|
||||
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void slf4j() {",
|
||||
" LOG.debug(\"str \" + toString());",
|
||||
" LOG.debug((Marker) null, \"str \" + toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" LOG.debug(\"{} \" + toString(), \"arg\");",
|
||||
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Formatter;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" void assertj() {",
|
||||
" assertThat(0).overridingErrorMessage(\"%s str\", toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s\", toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"%s%s\", toString(), toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s word %s\", toString(), new A().hashCode());",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s word %s\", toString(), hashCode() / 2);",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void guava() {",
|
||||
" checkArgument(true, \"str %s\", toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" checkArgument(true, \"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void jdk() {",
|
||||
" String.format(\"str %s\", toString());",
|
||||
" String.format(Locale.ROOT, \"str %s\", toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" String.format(\"{} \" + toString(), \"arg\");",
|
||||
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
" void slf4j() {",
|
||||
" LOG.debug(\"str {}\", toString());",
|
||||
" LOG.debug((Marker) null, \"str {}\", toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" LOG.debug(\"{} \" + toString(), \"arg\");",
|
||||
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -24,15 +24,15 @@ public final class JUnitMethodDeclarationCheckTest {
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class A {",
|
||||
" @BeforeAll void setUp1() {}",
|
||||
" @BeforeAll void beforeAll1() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @BeforeAll public void setUp2() {}",
|
||||
" @BeforeAll public void beforeAll2() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @BeforeAll protected void setUp3() {}",
|
||||
" @BeforeAll protected void beforeAll3() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @BeforeAll private void setUp4() {}",
|
||||
" @BeforeAll private void beforeAll4() {}",
|
||||
"",
|
||||
" @BeforeEach void setup5() {}",
|
||||
" @BeforeEach void setUp5() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @BeforeEach public void setUp6() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
@@ -48,13 +48,13 @@ public final class JUnitMethodDeclarationCheckTest {
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @AfterEach private void tearDown4() {}",
|
||||
"",
|
||||
" @AfterAll void tearDown5() {}",
|
||||
" @AfterAll void afterAll5() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @AfterAll public void tearDown6() {}",
|
||||
" @AfterAll public void afterAll6() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @AfterAll protected void tearDown7() {}",
|
||||
" @AfterAll protected void afterAll7() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @AfterAll private void tearDown8() {}",
|
||||
" @AfterAll private void afterAll8() {}",
|
||||
"",
|
||||
" @Test void method1() {}",
|
||||
" // BUG: Diagnostic contains:",
|
||||
@@ -92,11 +92,11 @@ public final class JUnitMethodDeclarationCheckTest {
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class B extends A {",
|
||||
" @Override @BeforeAll void setUp1() {}",
|
||||
" @Override @BeforeAll public void setUp2() {}",
|
||||
" @Override @BeforeAll protected void setUp3() {}",
|
||||
" @Override @BeforeAll void beforeAll1() {}",
|
||||
" @Override @BeforeAll public void beforeAll2() {}",
|
||||
" @Override @BeforeAll protected void beforeAll3() {}",
|
||||
"",
|
||||
" @Override @BeforeEach void setup5() {}",
|
||||
" @Override @BeforeEach void setUp5() {}",
|
||||
" @Override @BeforeEach public void setUp6() {}",
|
||||
" @Override @BeforeEach protected void setUp7() {}",
|
||||
"",
|
||||
@@ -104,9 +104,9 @@ public final class JUnitMethodDeclarationCheckTest {
|
||||
" @Override @AfterEach public void tearDown2() {}",
|
||||
" @Override @AfterEach protected void tearDown3() {}",
|
||||
"",
|
||||
" @Override @AfterAll void tearDown5() {}",
|
||||
" @Override @AfterAll public void tearDown6() {}",
|
||||
" @Override @AfterAll protected void tearDown7() {}",
|
||||
" @Override @AfterAll void afterAll5() {}",
|
||||
" @Override @AfterAll public void afterAll6() {}",
|
||||
" @Override @AfterAll protected void afterAll7() {}",
|
||||
"",
|
||||
" @Override @Test void method1() {}",
|
||||
" @Override @Test void testMethod2() {}",
|
||||
@@ -163,10 +163,10 @@ public final class JUnitMethodDeclarationCheckTest {
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class A {",
|
||||
" @BeforeAll void setUp1() {}",
|
||||
" @BeforeEach void setUp2() {}",
|
||||
" @AfterEach void setUp3() {}",
|
||||
" @AfterAll void setUp4() {}",
|
||||
" @BeforeAll void beforeAll() {}",
|
||||
" @BeforeEach void setUp() {}",
|
||||
" @AfterEach void tearDown() {}",
|
||||
" @AfterAll void afterAll() {}",
|
||||
"",
|
||||
" @Test void foo() {}",
|
||||
" @ParameterizedTest void bar() {}",
|
||||
@@ -177,4 +177,36 @@ public final class JUnitMethodDeclarationCheckTest {
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replaceSetupAndTeardownMethods() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"in/A.java",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"",
|
||||
"class A {",
|
||||
" @BeforeAll public void setUp1() {}",
|
||||
" @BeforeEach protected void setUp2() {}",
|
||||
" @AfterEach private void setUp3() {}",
|
||||
" @AfterAll private void setUp4() {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"",
|
||||
"class A {",
|
||||
" @BeforeAll void beforeAll() {}",
|
||||
" @BeforeEach void setUp() {}",
|
||||
" @AfterEach void tearDown() {}",
|
||||
" @AfterAll void afterAll() {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
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;
|
||||
|
||||
public final class MockitoStubbingCheckTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(MockitoStubbingCheck.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(MockitoStubbingCheck.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.mockito.ArgumentMatchers.eq;",
|
||||
"import static org.mockito.ArgumentMatchers.notNull;",
|
||||
"import static org.mockito.Mockito.doAnswer;",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"",
|
||||
"import java.util.function.BiConsumer;",
|
||||
"import java.util.function.Consumer;",
|
||||
"import org.mockito.ArgumentMatchers;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Runnable runnable = mock(Runnable.class);",
|
||||
" doAnswer(inv -> null).when(runnable).run();",
|
||||
"",
|
||||
" Consumer<String> consumer = mock(Consumer.class);",
|
||||
" doAnswer(inv -> null).when(consumer).accept(\"foo\");",
|
||||
" doAnswer(inv -> null).when(consumer).accept(notNull());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq(\"foo\"));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(consumer).accept(eq(toString()));",
|
||||
"",
|
||||
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(0, \"foo\");",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(eq(0), notNull());",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(notNull(), eq(\"foo\"));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq(\"foo\"));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"in/A.java",
|
||||
"import static org.mockito.ArgumentMatchers.eq;",
|
||||
"import static org.mockito.Mockito.doAnswer;",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"",
|
||||
"import java.util.function.BiConsumer;",
|
||||
"import java.util.function.Consumer;",
|
||||
"import org.mockito.ArgumentMatchers;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Consumer<String> consumer = mock(Consumer.class);",
|
||||
" doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq(\"foo\"));",
|
||||
" doAnswer(inv -> null).when(consumer).accept(eq(toString()));",
|
||||
"",
|
||||
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq(\"foo\"));",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import static org.mockito.ArgumentMatchers.eq;",
|
||||
"import static org.mockito.Mockito.doAnswer;",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"",
|
||||
"import java.util.function.BiConsumer;",
|
||||
"import java.util.function.Consumer;",
|
||||
"import org.mockito.ArgumentMatchers;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Consumer<String> consumer = mock(Consumer.class);",
|
||||
" doAnswer(inv -> null).when(consumer).accept(\"foo\");",
|
||||
" doAnswer(inv -> null).when(consumer).accept(toString());",
|
||||
"",
|
||||
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(0, \"foo\");",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(hashCode(), toString());",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,8 @@ public final class RefasterCheckTest {
|
||||
"Stream",
|
||||
"String",
|
||||
"TestNGToAssertJ",
|
||||
"Time");
|
||||
"Time",
|
||||
"WebClient");
|
||||
/**
|
||||
* Matches the parts of the fully-qualified name of a template class that should be removed in
|
||||
* order to produce the associated {@link #TEMPLATE_GROUPS template group name}.
|
||||
|
||||
@@ -27,6 +27,7 @@ public final class StaticImportCheckTest {
|
||||
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
|
||||
"import static java.nio.charset.StandardCharsets.UTF_8;",
|
||||
"import static java.util.function.Predicate.not;",
|
||||
"import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;",
|
||||
"",
|
||||
"import com.google.common.base.Predicates;",
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
@@ -35,6 +36,8 @@ public final class StaticImportCheckTest {
|
||||
"import java.nio.charset.StandardCharsets;",
|
||||
"import java.util.Optional;",
|
||||
"import java.util.function.Predicate;",
|
||||
"import org.springframework.boot.test.context.SpringBootTest;",
|
||||
"import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
@@ -68,6 +71,10 @@ public final class StaticImportCheckTest {
|
||||
" Object o1 = StandardCharsets.UTF_8;",
|
||||
" Object o2 = UTF_8;",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Object e1 = WebEnvironment.RANDOM_PORT;",
|
||||
" Object e2 = RANDOM_PORT;",
|
||||
"",
|
||||
" Optional.empty();",
|
||||
" }",
|
||||
"",
|
||||
@@ -87,8 +94,12 @@ public final class StaticImportCheckTest {
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.nio.charset.StandardCharsets;",
|
||||
"import java.util.Objects;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.springframework.format.annotation.DateTimeFormat;",
|
||||
"import org.springframework.format.annotation.DateTimeFormat.ISO;",
|
||||
"import org.springframework.boot.test.context.SpringBootTest;",
|
||||
"import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m1() {",
|
||||
@@ -101,6 +112,10 @@ public final class StaticImportCheckTest {
|
||||
" Predicates.not(null);",
|
||||
" not(null);",
|
||||
"",
|
||||
" Arguments.arguments(\"foo\");",
|
||||
"",
|
||||
" Objects.requireNonNull(\"bar\");",
|
||||
"",
|
||||
" Object o = StandardCharsets.UTF_8;",
|
||||
" }",
|
||||
"",
|
||||
@@ -113,13 +128,19 @@ public final class StaticImportCheckTest {
|
||||
" @DateTimeFormat(iso = ISO.DATE) String date,",
|
||||
" @DateTimeFormat(iso = ISO.DATE_TIME) String dateTime,",
|
||||
" @DateTimeFormat(iso = ISO.TIME) String time) {}",
|
||||
"",
|
||||
" @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)",
|
||||
" final class Test {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
|
||||
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
|
||||
"import static java.nio.charset.StandardCharsets.UTF_8;",
|
||||
"import static java.util.Objects.requireNonNull;",
|
||||
"import static java.util.function.Predicate.not;",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;",
|
||||
"import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE;",
|
||||
"import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME;",
|
||||
"import static org.springframework.format.annotation.DateTimeFormat.ISO.TIME;",
|
||||
@@ -128,6 +149,10 @@ public final class StaticImportCheckTest {
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.nio.charset.StandardCharsets;",
|
||||
"import java.util.Objects;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.springframework.boot.test.context.SpringBootTest;",
|
||||
"import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;",
|
||||
"import org.springframework.format.annotation.DateTimeFormat;",
|
||||
"import org.springframework.format.annotation.DateTimeFormat.ISO;",
|
||||
"",
|
||||
@@ -142,6 +167,10 @@ public final class StaticImportCheckTest {
|
||||
" Predicates.not(null);",
|
||||
" not(null);",
|
||||
"",
|
||||
" arguments(\"foo\");",
|
||||
"",
|
||||
" requireNonNull(\"bar\");",
|
||||
"",
|
||||
" Object o = UTF_8;",
|
||||
" }",
|
||||
"",
|
||||
@@ -154,6 +183,9 @@ public final class StaticImportCheckTest {
|
||||
" @DateTimeFormat(iso = DATE) String date,",
|
||||
" @DateTimeFormat(iso = DATE_TIME) String dateTime,",
|
||||
" @DateTimeFormat(iso = TIME) String time) {}",
|
||||
"",
|
||||
" @SpringBootTest(webEnvironment = RANDOM_PORT)",
|
||||
" final class Test {}",
|
||||
"}")
|
||||
.doTest(BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public final class TimeZoneUsageCheckTest {
|
||||
"import java.time.LocalDate;",
|
||||
"import java.time.LocalDateTime;",
|
||||
"import java.time.LocalTime;",
|
||||
"import java.time.ZoneId;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
@@ -78,6 +79,24 @@ public final class TimeZoneUsageCheckTest {
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" LocalTime.now(UTC);",
|
||||
" }",
|
||||
"",
|
||||
" abstract class ForwardingClock extends Clock {",
|
||||
" private final Clock clock;",
|
||||
"",
|
||||
" ForwardingClock(Clock clock) {",
|
||||
" this.clock = clock;",
|
||||
" }",
|
||||
"",
|
||||
" @Override",
|
||||
" public ZoneId getZone() {",
|
||||
" return clock.getZone();",
|
||||
" }",
|
||||
"",
|
||||
" @Override",
|
||||
" public Clock withZone(ZoneId zone) {",
|
||||
" return clock.withZone(zone);",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ final class AssertJOptionalTemplatesTest implements RefasterTemplateTestCase {
|
||||
assertThat(Optional.of(4)).isPresent().hasValue(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAbstractOptionalAssertContainsSame() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(Optional.of(1)).get().isSameAs(1),
|
||||
assertThat(Optional.of(2)).isPresent().isSameAs(2));
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatOptionalHasValueMatching() {
|
||||
return assertThat(Optional.of("foo").filter(String::isEmpty)).isPresent();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ final class AssertJOptionalTemplatesTest implements RefasterTemplateTestCase {
|
||||
assertThat(Optional.of(4)).hasValue(4));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAbstractOptionalAssertContainsSame() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(Optional.of(1)).containsSame(1), assertThat(Optional.of(2)).containsSame(2));
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatOptionalHasValueMatching() {
|
||||
return assertThat(Optional.of("foo")).get().matches(String::isEmpty);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ final class ImmutableListMultimapTemplatesTest implements RefasterTemplateTestCa
|
||||
.collect(
|
||||
flatteningToImmutableListMultimap(
|
||||
Map.Entry::getKey, e -> e.getValue().stream().map(Math::toIntExact))),
|
||||
Multimaps.asMap((Multimap<String, Long>) ImmutableSetMultimap.of("bar", 2L)).entrySet()
|
||||
Multimaps.asMap((Multimap<String, Long>) ImmutableSetMultimap.of("bar", 2L))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(
|
||||
flatteningToImmutableListMultimap(
|
||||
|
||||
@@ -59,10 +59,6 @@ final class ImmutableListTemplatesTest implements RefasterTemplateTestCase {
|
||||
Stream.of(2).collect(collectingAndThen(toList(), ImmutableList::copyOf)));
|
||||
}
|
||||
|
||||
ImmutableList<Integer> testImmutableListAsList() {
|
||||
return ImmutableList.of(1, 2, 3).asList();
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableList<Integer>> testImmutableListSortedCopyOf() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.sortedCopyOf(naturalOrder(), ImmutableSet.of(1)),
|
||||
|
||||
@@ -57,10 +57,6 @@ final class ImmutableListTemplatesTest implements RefasterTemplateTestCase {
|
||||
Stream.of(1).collect(toImmutableList()), Stream.of(2).collect(toImmutableList()));
|
||||
}
|
||||
|
||||
ImmutableList<Integer> testImmutableListAsList() {
|
||||
return ImmutableList.of(1, 2, 3);
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableList<Integer>> testImmutableListSortedCopyOf() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.sortedCopyOf(ImmutableSet.of(1)),
|
||||
|
||||
@@ -72,7 +72,8 @@ final class ImmutableSetMultimapTemplatesTest implements RefasterTemplateTestCas
|
||||
.collect(
|
||||
flatteningToImmutableSetMultimap(
|
||||
Map.Entry::getKey, e -> e.getValue().stream().map(Math::toIntExact))),
|
||||
Multimaps.asMap((Multimap<String, Long>) ImmutableSetMultimap.of("bar", 2L)).entrySet()
|
||||
Multimaps.asMap((Multimap<String, Long>) ImmutableSetMultimap.of("bar", 2L))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(
|
||||
flatteningToImmutableSetMultimap(
|
||||
|
||||
@@ -34,10 +34,6 @@ final class OptionalTemplatesTest implements RefasterTemplateTestCase {
|
||||
return Optional::get;
|
||||
}
|
||||
|
||||
Stream<Object> testOptionalToStream() {
|
||||
return Stream.concat(Streams.stream(Optional.empty()), Streams.stream(Optional.of("foo")));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFirstIteratorElement() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableSet.of("foo").iterator().hasNext()
|
||||
|
||||
@@ -34,10 +34,6 @@ final class OptionalTemplatesTest implements RefasterTemplateTestCase {
|
||||
return Optional::orElseThrow;
|
||||
}
|
||||
|
||||
Stream<Object> testOptionalToStream() {
|
||||
return Stream.concat(Optional.empty().stream(), Optional.of("foo").stream());
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFirstIteratorElement() {
|
||||
return ImmutableSet.of(
|
||||
stream(ImmutableSet.of("foo").iterator()).findFirst(),
|
||||
|
||||
@@ -49,6 +49,14 @@ final class ReactorTemplatesTest implements RefasterTemplateTestCase {
|
||||
return Mono.just("foo").flatMapMany(s -> Mono.just(s + s));
|
||||
}
|
||||
|
||||
Flux<String> testMonoFlux() {
|
||||
return Flux.concat(Mono.just("foo"));
|
||||
}
|
||||
|
||||
Flux<String> testFluxIdentity() {
|
||||
return Flux.concat(Flux.just("foo"));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Optional<String>>> testMonoCollectToOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").map(Optional::of).defaultIfEmpty(Optional.empty()),
|
||||
@@ -59,6 +67,14 @@ final class ReactorTemplatesTest implements RefasterTemplateTestCase {
|
||||
return ImmutableSet.of(PublisherProbe.of(Mono.empty()), PublisherProbe.of(Flux.empty()));
|
||||
}
|
||||
|
||||
StepVerifier.FirstStep<Integer> testStepVerifierFromMono() {
|
||||
return StepVerifier.create(Mono.just(1));
|
||||
}
|
||||
|
||||
StepVerifier.FirstStep<Integer> testStepVerifierFromFlux() {
|
||||
return StepVerifier.create(Flux.just(1));
|
||||
}
|
||||
|
||||
StepVerifier.Step<Integer> testStepVerifierStepExpectNextEmpty() {
|
||||
return StepVerifier.create(Mono.just(0)).expectNext();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ final class ReactorTemplatesTest implements RefasterTemplateTestCase {
|
||||
return Mono.just("foo").flatMap(s -> Mono.just(s + s)).flux();
|
||||
}
|
||||
|
||||
Flux<String> testMonoFlux() {
|
||||
return Mono.just("foo").flux();
|
||||
}
|
||||
|
||||
Flux<String> testFluxIdentity() {
|
||||
return Flux.just("foo");
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Optional<String>>> testMonoCollectToOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flux().collect(toOptional()),
|
||||
@@ -60,6 +68,14 @@ final class ReactorTemplatesTest implements RefasterTemplateTestCase {
|
||||
return ImmutableSet.of(PublisherProbe.empty(), PublisherProbe.empty());
|
||||
}
|
||||
|
||||
StepVerifier.FirstStep<Integer> testStepVerifierFromMono() {
|
||||
return Mono.just(1).as(StepVerifier::create);
|
||||
}
|
||||
|
||||
StepVerifier.FirstStep<Integer> testStepVerifierFromFlux() {
|
||||
return Flux.just(1).as(StepVerifier::create);
|
||||
}
|
||||
|
||||
StepVerifier.Step<Integer> testStepVerifierStepExpectNextEmpty() {
|
||||
return StepVerifier.create(Mono.just(0));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
final class WebClientTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(fromValue(""));
|
||||
}
|
||||
|
||||
ImmutableSet<?> testBodyValue() {
|
||||
return ImmutableSet.of(
|
||||
WebClient.create("foo").post().body(fromValue("bar")),
|
||||
WebTestClient.bindToServer().build().post().body(fromValue("bar")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
final class WebClientTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(fromValue(""));
|
||||
}
|
||||
|
||||
ImmutableSet<?> testBodyValue() {
|
||||
return ImmutableSet.of(
|
||||
WebClient.create("foo").post().bodyValue("bar"),
|
||||
WebTestClient.bindToServer().build().post().bodyValue("bar"));
|
||||
}
|
||||
}
|
||||
148
pom.xml
148
pom.xml
@@ -69,6 +69,21 @@
|
||||
arguments. In particular, JaCoCo relies on this for the configuration
|
||||
of its Java agent. -->
|
||||
<argLine>
|
||||
<!-- Error Prone makes extensive use of unsupported
|
||||
`javac`-internal APIs, in some cases even reflectively inspecting
|
||||
them. These APIs are accessed at compile time and when running
|
||||
tests. The former case is covered by flags in `.mvn/jvm.config`;
|
||||
the latter is covered here. -->
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||
--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
|
||||
--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
|
||||
<!-- The test JVMs are short-running. By disabling certain
|
||||
expensive JIT optimizations we actually speed up most tests. -->
|
||||
-XX:TieredStopAtLevel=1
|
||||
@@ -110,18 +125,19 @@
|
||||
<!-- Dependency and plugin versions that are referenced in more than
|
||||
one place. We use these to keep dependencies in sync. Version numbers
|
||||
that need to be referenced only once should *not* be listed here. -->
|
||||
<version.auto-service>1.0</version.auto-service>
|
||||
<version.auto-service>1.0.1</version.auto-service>
|
||||
<version.auto-value>1.8.2</version.auto-value>
|
||||
<version.error-prone>${version.error-prone-orig}</version.error-prone>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.8.0</version.error-prone-orig>
|
||||
<version.error-prone-orig>2.10.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.4</version.error-prone-slf4j>
|
||||
<version.findbugs-format-string>3.0.0</version.findbugs-format-string>
|
||||
<version.guava-beta-checker>1.0</version.guava-beta-checker>
|
||||
<version.jdk>11</version.jdk>
|
||||
<version.maven>3.6.3</version.maven>
|
||||
<version.mockito>3.11.2</version.mockito>
|
||||
<version.mockito>4.0.0</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.9.1</version.nullaway>
|
||||
<version.nullaway>0.9.2</version.nullaway>
|
||||
<!-- XXX: Two other dependencies are potentially of interest:
|
||||
`com.palantir.assertj-automation:assertj-refaster-rules` and
|
||||
`com.palantir.baseline:baseline-refaster-rules` contain Refaster rules
|
||||
@@ -129,8 +145,8 @@
|
||||
`RefasterRuleBuilderScanner` to convert those to `.refaster` files so
|
||||
that we can pick them up. (But in case of `baseline-refaster-rules`
|
||||
perhaps we can simply incorporate all of them.) -->
|
||||
<version.palantir-assertj-automation>0.2.1</version.palantir-assertj-automation>
|
||||
<version.palantir-baseline>4.7.0</version.palantir-baseline>
|
||||
<version.palantir-assertj-automation>0.3.0</version.palantir-assertj-automation>
|
||||
<version.palantir-baseline>4.42.0</version.palantir-baseline>
|
||||
<version.surefire>2.22.2</version.surefire>
|
||||
</properties>
|
||||
|
||||
@@ -174,24 +190,29 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson</groupId>
|
||||
<artifactId>jackson-bom</artifactId>
|
||||
<version>2.12.4</version>
|
||||
<version>2.13.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto</groupId>
|
||||
<artifactId>auto-common</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
<version>${version.auto-service}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value</artifactId>
|
||||
<version>${version.auto-value}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<version>1.8.2</version>
|
||||
<version>${version.auto-value}</version>
|
||||
</dependency>
|
||||
<!-- Specified as a workaround for
|
||||
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
|
||||
@@ -220,7 +241,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>30.1.1-jre</version>
|
||||
<version>31.0.1-jre</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -260,7 +281,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2020.0.9</version>
|
||||
<version>2020.0.13</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -272,12 +293,12 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<version>1.6.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.1.10</version>
|
||||
<version>2.1.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
@@ -309,12 +330,12 @@
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.20.2</version>
|
||||
<version>3.21.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.16.0</version>
|
||||
<version>3.19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -324,7 +345,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>5.7.2</version>
|
||||
<version>5.8.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -346,10 +367,15 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>5.3.9</version>
|
||||
<version>5.3.13</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>2.5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
@@ -364,7 +390,7 @@
|
||||
<plugin>
|
||||
<groupId>com.coveo</groupId>
|
||||
<artifactId>fmt-maven-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<version>2.12</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
@@ -385,6 +411,7 @@
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>verify-pom-sorting</id>
|
||||
<goals>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
@@ -392,27 +419,10 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.lewisd</groupId>
|
||||
<artifactId>lint-maven-plugin</artifactId>
|
||||
<version>0.0.11</version>
|
||||
<configuration>
|
||||
<failOnViolation>false</failOnViolation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>validate-pom</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>validate</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
<artifactId>forbiddenapis</artifactId>
|
||||
<version>3.1</version>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<bundledSignatures>
|
||||
<bundledSignature>jdk-internal</bundledSignature>
|
||||
@@ -605,6 +615,10 @@
|
||||
<!-- Instead, please use
|
||||
`com.google.common.base.Preconditions`. -->
|
||||
</property>
|
||||
<property name="illegalClasses" value="org\.assertj\.core\.util\.Streams(\..*?)?">
|
||||
<!-- Instead, please use
|
||||
`com.google.common.collect.Streams`. -->
|
||||
</property>
|
||||
<property name="illegalClasses" value="org\.junit\.jupiter\.api\.Assertions(\..*?)?">
|
||||
<!-- Instead, please use
|
||||
`org.assertj.core.api.Assertions`. -->
|
||||
@@ -622,7 +636,7 @@
|
||||
</property>
|
||||
<property name="illegalClasses" value="org\.testng\.AssertJUnit(\..*?)?">
|
||||
<!-- Instead, please use
|
||||
`com.google.common.base.Preconditions`. -->
|
||||
`org.assertj.core.api.Assertions`. -->
|
||||
</property>
|
||||
<property name="regexp" value="true" />
|
||||
</module>
|
||||
@@ -631,6 +645,10 @@
|
||||
<module name="InnerAssignment" />
|
||||
<module name="InvalidJavadocPosition" />
|
||||
<module name="JavadocBlockTagLocation" />
|
||||
<module name="MatchXpath">
|
||||
<property name="query" value="//BLOCK_COMMENT_BEGIN[./COMMENT_CONTENT[contains(@text, '@author')]]" />
|
||||
<message key="matchxpath.match" value="Avoid the `@author` Javadoc tag; Git history suffices." />
|
||||
</module>
|
||||
<module name="MissingDeprecated" />
|
||||
<module name="MutableException" />
|
||||
<module name="NeedBraces" />
|
||||
@@ -648,13 +666,6 @@
|
||||
<module name="SimplifyBooleanReturn" />
|
||||
<module name="SuppressWarningsHolder" />
|
||||
<module name="TrailingComment" />
|
||||
<module name="WriteTag">
|
||||
<property name="tag" value="@author" />
|
||||
<property name="tagFormat" value="\S" />
|
||||
<property name="tagSeverity" value="error" />
|
||||
<property name="severity" value="ignore" />
|
||||
</module>
|
||||
<module name="UnnecessaryParentheses" />
|
||||
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration" />
|
||||
<module name="UnnecessarySemicolonInEnumeration" />
|
||||
<module name="UnnecessarySemicolonInTryWithResources" />
|
||||
@@ -675,7 +686,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>8.41.1</version>
|
||||
<version>9.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -736,11 +747,14 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<configuration>
|
||||
<retryFailedDeploymentCount>3</retryFailedDeploymentCount>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.0.0-M3</version>
|
||||
<version>3.0.0</version>
|
||||
<configuration>
|
||||
<fail>false</fail>
|
||||
<rules>
|
||||
@@ -777,7 +791,7 @@
|
||||
<dependency>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>extra-enforcer-rules</artifactId>
|
||||
<version>1.3</version>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -836,7 +850,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<configuration>
|
||||
<!-- All relevant doclint checks are performed during
|
||||
the compilation phase; no need to recheck during
|
||||
@@ -1050,7 +1064,7 @@
|
||||
<plugin>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>2.3.0</version>
|
||||
<configuration>
|
||||
<exclusionPatterns>
|
||||
<!-- The plugin suggests replacing Guava's
|
||||
@@ -1059,6 +1073,12 @@
|
||||
methods don't allow one to convey immutability at
|
||||
the type system level. -->
|
||||
<exclusionPattern>com/google/common/collect/Immutable(List|Map|Set)\.(copyOf|of):.*</exclusionPattern>
|
||||
<!-- The plugin suggests replacing usages of
|
||||
Guava's `Iterables` class with
|
||||
`java.util.stream.Stream` equivalents, but the
|
||||
alternative is often more verbose, requiring
|
||||
unnecessary conversions to and from streams. -->
|
||||
<exclusionPattern>com/google/common/collect/Iterables\..*</exclusionPattern>
|
||||
</exclusionPatterns>
|
||||
<failOnViolations>false</failOnViolations>
|
||||
<ignorePackages>
|
||||
@@ -1071,7 +1091,7 @@
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>modernize</id>
|
||||
<id>run-modernizer</id>
|
||||
<goals>
|
||||
<goal>modernizer</goal>
|
||||
</goals>
|
||||
@@ -1087,7 +1107,7 @@
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.6.7</version>
|
||||
<version>1.7.3</version>
|
||||
<configuration>
|
||||
<!-- Use multiple threads to speed things up. Extend
|
||||
timeouts to prevent false positives as a result of
|
||||
@@ -1100,7 +1120,7 @@
|
||||
<dependency>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-junit5-plugin</artifactId>
|
||||
<version>0.14</version>
|
||||
<version>0.15</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -1115,7 +1135,7 @@
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.9.0.2155</version>
|
||||
<version>3.9.1.2184</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
@@ -1250,10 +1270,6 @@
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
<artifactId>sortpom-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.lewisd</groupId>
|
||||
<artifactId>lint-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
<artifactId>forbiddenapis</artifactId>
|
||||
@@ -1435,8 +1451,13 @@
|
||||
-Xep:BetaApi:OFF
|
||||
<!-- We don't target JDK 7. -->
|
||||
-Xep:Java7ApiChecker:OFF
|
||||
<!-- We don't target JDK 8. -->
|
||||
-Xep:Java8ApiChecker:OFF
|
||||
<!-- We don't target Android. -->
|
||||
-Xep:StaticOrDefaultInterfaceMethod:OFF
|
||||
<!-- XXX: This check flags false positives.
|
||||
See https://github.com/google/error-prone/issues/2679. -->
|
||||
-Xep:VoidMissingNullable:OFF
|
||||
-XepOpt:NullAway:AnnotatedPackages=tech.picnic
|
||||
-XepOpt:NullAway:AssertsEnabled=true
|
||||
-XepOpt:NullAway:CheckOptionalEmptiness=true
|
||||
@@ -1473,9 +1494,9 @@
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- The `build-checks` and `error-prone` profiles enable a whole
|
||||
bunch of additional compile checks. This profile ensures that by
|
||||
default those warnings break the build. Disabling this profile
|
||||
allows one to collect all build warnings without failing the build. -->
|
||||
bunch of additional compile checks. By default those warnings break
|
||||
the build. This profile allows one to collect all build warnings
|
||||
without failing the build. -->
|
||||
<id>disallow-warnings</id>
|
||||
<activation>
|
||||
<property>
|
||||
@@ -1492,13 +1513,6 @@
|
||||
<verifyFail>stop</verifyFail>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.lewisd</groupId>
|
||||
<artifactId>lint-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<failOnViolation>true</failOnViolation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
<artifactId>forbiddenapis</artifactId>
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.google.common.collect.Multimaps;
|
||||
import com.google.errorprone.CodeTransformer;
|
||||
import com.google.errorprone.CompositeCodeTransformer;
|
||||
import com.google.errorprone.refaster.RefasterRuleBuilderScanner;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
@@ -23,6 +23,7 @@ import com.sun.tools.javac.main.JavaCompiler;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.List;
|
||||
@@ -62,7 +63,7 @@ final class RefasterRuleResourceCompilerTaskListener implements TaskListener {
|
||||
try {
|
||||
outputCodeTransformers(rule.getValue(), getOutputFile(taskEvent, rule.getKey()));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
throw new UncheckedIOException("Failed to persist compiled Refaster templates", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,11 +72,12 @@ final class RefasterRuleResourceCompilerTaskListener implements TaskListener {
|
||||
return Boolean.TRUE.equals(
|
||||
new TreeScanner<Boolean, Void>() {
|
||||
@Override
|
||||
public Boolean visitAnnotation(AnnotationTree node, Void ctx) {
|
||||
public Boolean visitAnnotation(AnnotationTree node, Void v) {
|
||||
Symbol sym = ASTHelpers.getSymbol(node);
|
||||
return (sym != null
|
||||
&& sym.getQualifiedName().contentEquals(AfterTemplate.class.getCanonicalName()))
|
||||
|| super.visitAnnotation(node, ctx);
|
||||
&& sym.getQualifiedName()
|
||||
.contentEquals(BeforeTemplate.class.getCanonicalName()))
|
||||
|| super.visitAnnotation(node, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,13 +90,13 @@ final class RefasterRuleResourceCompilerTaskListener implements TaskListener {
|
||||
private ImmutableListMultimap<ClassTree, CodeTransformer> compileRefasterTemplates(
|
||||
ClassTree tree) {
|
||||
ListMultimap<ClassTree, CodeTransformer> rules = ArrayListMultimap.create();
|
||||
new TreeScanner<Void, Context>() {
|
||||
new TreeScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitClass(ClassTree node, Context ctx) {
|
||||
rules.putAll(node, RefasterRuleBuilderScanner.extractRules(node, ctx));
|
||||
return super.visitClass(node, ctx);
|
||||
public Void visitClass(ClassTree node, Void v) {
|
||||
rules.putAll(node, RefasterRuleBuilderScanner.extractRules(node, context));
|
||||
return super.visitClass(node, null);
|
||||
}
|
||||
}.scan(tree, context);
|
||||
}.scan(tree, null);
|
||||
return ImmutableListMultimap.copyOf(rules);
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ final class RefasterRuleResourceCompilerTaskListener implements TaskListener {
|
||||
|
||||
private static void outputCodeTransformers(List<CodeTransformer> rules, FileObject target)
|
||||
throws IOException {
|
||||
try (ObjectOutputStream output = new ObjectOutputStream(target.openOutputStream())) {
|
||||
try (ObjectOutput output = new ObjectOutputStream(target.openOutputStream())) {
|
||||
output.writeObject(CompositeCodeTransformer.compose(rules));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user