mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 15:49:33 +00:00
Compare commits
15 Commits
v0.7.0
...
nkooij/tim
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ced020ba6 | ||
|
|
389928ce43 | ||
|
|
d88f226b30 | ||
|
|
ba91c6bed7 | ||
|
|
85f402b089 | ||
|
|
ad8c0a472c | ||
|
|
0af127652e | ||
|
|
cede5e451b | ||
|
|
134895090f | ||
|
|
226bfd0cee | ||
|
|
89a3c605fe | ||
|
|
63273a2609 | ||
|
|
79768a2428 | ||
|
|
dd8d094b5a | ||
|
|
4830b5b2cd |
21
.github/ISSUE_TEMPLATE/feature_request.md
vendored
21
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -17,24 +17,23 @@ you'd like to be solved through Error Prone Support. -->
|
||||
|
||||
- [ ] Support a stylistic preference.
|
||||
- [ ] Avoid a common gotcha, or potential problem.
|
||||
- [ ] Improve performance.
|
||||
|
||||
<!--
|
||||
Here, provide a clear and concise description of the desired change.
|
||||
|
||||
If possible, provide a simple and minimal example using the following format:
|
||||
|
||||
I would like to rewrite the following code:
|
||||
```java
|
||||
// XXX: Write the code to match here.
|
||||
```
|
||||
|
||||
to:
|
||||
```java
|
||||
// XXX: Write the desired code here.
|
||||
```
|
||||
-->
|
||||
|
||||
I would like to rewrite the following code:
|
||||
```java
|
||||
// XXX: Write the code to match here.
|
||||
```
|
||||
|
||||
to:
|
||||
```java
|
||||
// XXX: Write the desired code here.
|
||||
```
|
||||
|
||||
### Considerations
|
||||
|
||||
<!--
|
||||
|
||||
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
uses: actions/setup-java@v3.6.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: ${{ matrix.distribution }}
|
||||
|
||||
8
.github/workflows/deploy-website.yaml
vendored
8
.github/workflows/deploy-website.yaml
vendored
@@ -13,12 +13,12 @@ jobs:
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
- uses: ruby/setup-ruby@v1.126.0
|
||||
- uses: ruby/setup-ruby@v1.120.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
- name: Configure Github Pages
|
||||
uses: actions/configure-pages@v2.1.3
|
||||
uses: actions/configure-pages@v2.1.2
|
||||
- name: Generate documentation
|
||||
run: ./generate-docs.sh
|
||||
- name: Build website with Jekyll
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
# "Refaster rules" terminology on our website and in the code.
|
||||
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
|
||||
- name: Upload website as artifact
|
||||
uses: actions/upload-pages-artifact@v1.0.5
|
||||
uses: actions/upload-pages-artifact@v1.0.4
|
||||
with:
|
||||
path: ./website/_site
|
||||
deploy:
|
||||
@@ -46,4 +46,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1.2.3
|
||||
uses: actions/deploy-pages@v1.2.2
|
||||
|
||||
37
.github/workflows/pitest-analyze-pr.yml
vendored
37
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -1,37 +0,0 @@
|
||||
# Performs mutation testing analysis on the files changed by a pull request and
|
||||
# uploads the results. The associated PR is subsequently updated by the
|
||||
# `pitest-update-pr.yml` workflow. See https://blog.pitest.org/oss-pitest-pr/
|
||||
# for details.
|
||||
name: "Mutation testing"
|
||||
on:
|
||||
pull_request:
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
analyze-pr:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
with:
|
||||
java-version: 17.0.4
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Run Pitest
|
||||
# By running with features `+GIT(from[HEAD~1]), +gitci`, Pitest only
|
||||
# analyzes lines changed in the associated pull request, as GitHub
|
||||
# exposes the changes unique to the PR as a single commit on top of the
|
||||
# target branch. See https://blog.pitest.org/pitest-pr-setup for
|
||||
# details.
|
||||
run: mvn test pitest:mutationCoverage -DargLine.xmx=2048m -Dverification.skip -Dfeatures="+GIT(from[HEAD~1]), +gitci"
|
||||
- name: Aggregate Pitest reports
|
||||
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
|
||||
- name: Upload Pitest reports as artifact
|
||||
uses: actions/upload-artifact@v3.1.1
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
35
.github/workflows/pitest-update-pr.yml
vendored
35
.github/workflows/pitest-update-pr.yml
vendored
@@ -1,35 +0,0 @@
|
||||
# Updates a pull request based on the corresponding mutation testing analysis
|
||||
# performed by the `pitest-analyze-pr.yml` workflow. See
|
||||
# https://blog.pitest.org/oss-pitest-pr/ for details.
|
||||
name: "Mutation testing: post results"
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Mutation testing"]
|
||||
types:
|
||||
- completed
|
||||
permissions:
|
||||
actions: read
|
||||
checks: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
jobs:
|
||||
update-pr:
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.1.0
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.8.0
|
||||
with:
|
||||
java-version: 17.0.4
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@v2.24.2
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
- name: Update PR
|
||||
run: mvn -DrepoToken="${{ secrets.GITHUB_TOKEN }}" pitest-github:updatePR
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"^ruby\\/setup-ruby$"
|
||||
"^com\\.palantir\\.baseline:baseline-error-prone$"
|
||||
],
|
||||
"schedule": "* * 1 * *"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2023 Picnic Technologies BV
|
||||
Copyright (c) 2017-2022 Picnic Technologies BV
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -166,7 +166,7 @@ Some other commands one may find relevant:
|
||||
|
||||
- `mvn fmt:format` formats the code using
|
||||
[`google-java-format`][google-java-format].
|
||||
- `./run-mutation-tests.sh` runs mutation tests using [Pitest][pitest]. The
|
||||
- `./run-mutation-tests.sh` runs mutation tests using [PIT][pitest]. The
|
||||
results can be reviewed by opening the respective
|
||||
`target/pit-reports/index.html` files. For more information check the [PIT
|
||||
Maven plugin][pitest-maven].
|
||||
|
||||
@@ -9,14 +9,13 @@
|
||||
set -e -u -o pipefail
|
||||
|
||||
if [ "${#}" -gt 1 ]; then
|
||||
echo "Usage: ${0} [PatchChecks]"
|
||||
echo "Usage: ./$(basename "${0}") [PatchChecks]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
patchChecks=${1:-}
|
||||
|
||||
mvn clean test-compile fmt:format \
|
||||
-s "$(dirname "${0}")/settings.xml" \
|
||||
-T 1.0C \
|
||||
-Perror-prone \
|
||||
-Perror-prone-fork \
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Arcmutate license for Error Prone Support, requested by sending an email to
|
||||
# support@arcmutate.com.
|
||||
expires=07/11/2023
|
||||
keyVersion=1
|
||||
signature=MhZxMbnO6UovNfllM0JuVWkZyvRT3/G5o/uT0Mm36c7200VpZNVu03gTAGivnl9W5RzvZhfpIHccuQ5ctjQkrqhsFSrl4fyqPqu3y5V2fsHIdFXP/G72EGj6Kay9ndLpaEHalqE0bEwxdnHMzEYq5y3O9vUPv8MhUl57xk+rvBo\=
|
||||
packages=tech.picnic.errorprone.*
|
||||
type=OSSS
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.7.0</version>
|
||||
<version>0.5.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -146,7 +146,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
@@ -23,7 +24,6 @@ import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import java.util.List;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags redundant {@code @Autowired} constructor annotations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@@ -62,6 +62,6 @@ public final class AutowiredConstructor extends BugChecker implements ClassTreeM
|
||||
* leave flagging the unused import to Error Prone's `RemoveUnusedImports` check.
|
||||
*/
|
||||
AnnotationTree annotation = Iterables.getOnlyElement(annotations);
|
||||
return describeMatch(annotation, SourceCode.deleteWithTrailingWhitespace(annotation, state));
|
||||
return describeMatch(annotation, SuggestedFix.delete(annotation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
@@ -21,7 +22,6 @@ import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags empty methods that seemingly can simply be deleted. */
|
||||
@AutoService(BugChecker.class)
|
||||
@@ -55,7 +55,7 @@ public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return describeMatch(tree, SourceCode.deleteWithTrailingWhitespace(tree, state));
|
||||
return describeMatch(tree, SuggestedFix.delete(tree));
|
||||
}
|
||||
|
||||
private static boolean isInPossibleTestHelperClass(VisitorState state) {
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.sun.source.util.SimpleTreeVisitor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.util.ASTHelpers.TargetType;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
@@ -33,7 +32,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags redundant identity conversions. */
|
||||
// XXX: Consider detecting cases where a flagged expression is passed to a method, and where removal
|
||||
// of the identity conversion would cause a different method overload to be selected. Depending on
|
||||
// of the identify conversion would cause a different method overload to be selected. Depending on
|
||||
// the target method such a modification may change the code's semantics or performance.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
@@ -46,13 +45,6 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> IS_CONVERSION_METHOD =
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
Primitives.allWrapperTypes().stream()
|
||||
.map(Class::getName)
|
||||
.collect(toImmutableSet()))
|
||||
.named("valueOf"),
|
||||
staticMethod().onClass(String.class.getName()).named("valueOf"),
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
"com.google.common.collect.ImmutableBiMap",
|
||||
@@ -68,8 +60,12 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
|
||||
"com.google.common.collect.ImmutableTable")
|
||||
.named("copyOf"),
|
||||
staticMethod()
|
||||
.onClass("com.google.errorprone.matchers.Matchers")
|
||||
.namedAnyOf("allOf", "anyOf"),
|
||||
.onClassAny(
|
||||
Primitives.allWrapperTypes().stream()
|
||||
.map(Class::getName)
|
||||
.collect(toImmutableSet()))
|
||||
.named("valueOf"),
|
||||
staticMethod().onClass(String.class.getName()).named("valueOf"),
|
||||
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
|
||||
staticMethod()
|
||||
.onClass("reactor.core.publisher.Flux")
|
||||
@@ -99,15 +95,6 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
if (sourceType.isPrimitive()
|
||||
&& state.getPath().getParentPath().getLeaf() instanceof MemberSelectTree) {
|
||||
/*
|
||||
* The result of the conversion method is dereferenced, while the source type is a primitive:
|
||||
* dropping the conversion would yield uncompilable code.
|
||||
*/
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return buildDescription(tree)
|
||||
.setMessage(
|
||||
"This method invocation appears redundant; remove it or suppress this warning and "
|
||||
|
||||
@@ -6,18 +6,15 @@ import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.LambdaExpressionTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.InstanceOfTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
@@ -42,19 +39,15 @@ public final class IsInstanceLambdaUsage extends BugChecker implements LambdaExp
|
||||
|
||||
@Override
|
||||
public Description matchLambdaExpression(LambdaExpressionTree tree, VisitorState state) {
|
||||
if (tree.getParameters().size() != 1 || tree.getBody().getKind() != Kind.INSTANCE_OF) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
VariableTree param = Iterables.getOnlyElement(tree.getParameters());
|
||||
InstanceOfTree instanceOf = (InstanceOfTree) tree.getBody();
|
||||
if (!ASTHelpers.getSymbol(param).equals(ASTHelpers.getSymbol(instanceOf.getExpression()))) {
|
||||
if (tree.getKind() != Kind.LAMBDA_EXPRESSION || tree.getBody().getKind() != Kind.INSTANCE_OF) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return describeMatch(
|
||||
tree,
|
||||
SuggestedFix.replace(
|
||||
tree, SourceCode.treeToString(instanceOf.getType(), state) + ".class::isInstance"));
|
||||
tree,
|
||||
SourceCode.treeToString(((InstanceOfTree) tree.getBody()).getType(), state)
|
||||
+ ".class::isInstance"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.hasMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.hasModifier;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.TEST_METHOD;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.hasMetaAnnotation;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags non-final and non package-private JUnit test class declarations,
|
||||
* unless abstract.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Non-abstract JUnit test classes should be declared package-private and final",
|
||||
linkType = CUSTOM,
|
||||
link = BUG_PATTERNS_BASE_URL + "JUnitClassModifiers",
|
||||
severity = SUGGESTION,
|
||||
tags = STYLE)
|
||||
public final class JUnitClassModifiers extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ClassTree> HAS_SPRING_CONFIGURATION_ANNOTATION =
|
||||
annotations(
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType("org.springframework.context.annotation.Configuration"),
|
||||
hasMetaAnnotation("org.springframework.context.annotation.Configuration")));
|
||||
private static final Matcher<ClassTree> TEST_CLASS_WITH_INCORRECT_MODIFIERS =
|
||||
allOf(
|
||||
hasMethod(TEST_METHOD),
|
||||
not(hasModifier(Modifier.ABSTRACT)),
|
||||
anyOf(
|
||||
hasModifier(Modifier.PRIVATE),
|
||||
hasModifier(Modifier.PROTECTED),
|
||||
hasModifier(Modifier.PUBLIC),
|
||||
allOf(not(hasModifier(Modifier.FINAL)), not(HAS_SPRING_CONFIGURATION_ANNOTATION))));
|
||||
|
||||
/** Instantiates a new {@link JUnitClassModifiers} instance. */
|
||||
public JUnitClassModifiers() {}
|
||||
|
||||
@Override
|
||||
public Description matchClass(ClassTree tree, VisitorState state) {
|
||||
if (!TEST_CLASS_WITH_INCORRECT_MODIFIERS.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
|
||||
SuggestedFixes.removeModifiers(
|
||||
tree.getModifiers(),
|
||||
state,
|
||||
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC))
|
||||
.ifPresent(fixBuilder::merge);
|
||||
|
||||
if (!HAS_SPRING_CONFIGURATION_ANNOTATION.matches(tree, state)) {
|
||||
SuggestedFixes.addModifiers(tree, state, Modifier.FINAL).ifPresent(fixBuilder::merge);
|
||||
}
|
||||
|
||||
return describeMatch(tree, fixBuilder.build());
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,19 @@ package tech.picnic.errorprone.bugpatterns;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.enclosingClass;
|
||||
import static com.google.errorprone.matchers.Matchers.hasModifier;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.JavaKeywords.isValidIdentifier;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.SETUP_OR_TEARDOWN_METHOD;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.TEST_METHOD;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.JavaKeywords.isReservedKeyword;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
@@ -24,15 +24,19 @@ import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.predicates.TypePredicate;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.ImportTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Name;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags non-canonical JUnit method declarations. */
|
||||
@@ -52,19 +56,35 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TEST_PREFIX = "test";
|
||||
private static final ImmutableSet<Modifier> ILLEGAL_MODIFIERS =
|
||||
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC);
|
||||
private static final Matcher<MethodTree> IS_LIKELY_OVERRIDDEN =
|
||||
allOf(
|
||||
not(hasModifier(Modifier.FINAL)),
|
||||
not(hasModifier(Modifier.PRIVATE)),
|
||||
enclosingClass(hasModifier(Modifier.ABSTRACT)));
|
||||
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC);
|
||||
private static final Matcher<MethodTree> HAS_UNMODIFIABLE_SIGNATURE =
|
||||
anyOf(
|
||||
annotations(AT_LEAST_ONE, isType("java.lang.Override")),
|
||||
allOf(
|
||||
Matchers.not(hasModifier(Modifier.FINAL)),
|
||||
Matchers.not(hasModifier(Modifier.PRIVATE)),
|
||||
enclosingClass(hasModifier(Modifier.ABSTRACT))));
|
||||
private static final MultiMatcher<MethodTree, AnnotationTree> TEST_METHOD =
|
||||
annotations(
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType("org.junit.jupiter.api.Test"),
|
||||
hasMetaAnnotation("org.junit.jupiter.api.TestTemplate")));
|
||||
private static final MultiMatcher<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
|
||||
annotations(
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType("org.junit.jupiter.api.AfterAll"),
|
||||
isType("org.junit.jupiter.api.AfterEach"),
|
||||
isType("org.junit.jupiter.api.BeforeAll"),
|
||||
isType("org.junit.jupiter.api.BeforeEach")));
|
||||
|
||||
/** Instantiates a new {@link JUnitMethodDeclaration} instance. */
|
||||
public JUnitMethodDeclaration() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
if (IS_LIKELY_OVERRIDDEN.matches(tree, state) || isOverride(tree, state)) {
|
||||
if (HAS_UNMODIFIABLE_SIGNATURE.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@@ -86,11 +106,10 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
|
||||
private void suggestTestMethodRenameIfApplicable(
|
||||
MethodTree tree, SuggestedFix.Builder fixBuilder, VisitorState state) {
|
||||
MethodSymbol symbol = ASTHelpers.getSymbol(tree);
|
||||
tryCanonicalizeMethodName(symbol)
|
||||
tryCanonicalizeMethodName(tree)
|
||||
.ifPresent(
|
||||
newName ->
|
||||
findMethodRenameBlocker(symbol, newName, state)
|
||||
findMethodRenameBlocker(newName, state)
|
||||
.ifPresentOrElse(
|
||||
blocker -> reportMethodRenameBlocker(tree, blocker, state),
|
||||
() -> fixBuilder.merge(SuggestedFixes.renameMethod(tree, newName, state))));
|
||||
@@ -122,29 +141,30 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
* consideration cannot be referenced directly.)
|
||||
* </ul>
|
||||
*/
|
||||
private static Optional<String> findMethodRenameBlocker(
|
||||
MethodSymbol method, String newName, VisitorState state) {
|
||||
if (isExistingMethodName(method.owner.type, newName, state)) {
|
||||
private static Optional<String> findMethodRenameBlocker(String methodName, VisitorState state) {
|
||||
if (isMethodInEnclosingClass(methodName, state)) {
|
||||
return Optional.of(
|
||||
String.format(
|
||||
"a method named `%s` is already defined in this class or a supertype", newName));
|
||||
String.format("a method named `%s` already exists in this class", methodName));
|
||||
}
|
||||
|
||||
if (isSimpleNameStaticallyImported(newName, state)) {
|
||||
return Optional.of(String.format("`%s` is already statically imported", newName));
|
||||
if (isSimpleNameStaticallyImported(methodName, state)) {
|
||||
return Optional.of(String.format("`%s` is already statically imported", methodName));
|
||||
}
|
||||
|
||||
if (!isValidIdentifier(newName)) {
|
||||
return Optional.of(String.format("`%s` is not a valid identifier", newName));
|
||||
if (isReservedKeyword(methodName)) {
|
||||
return Optional.of(String.format("`%s` is a reserved keyword", methodName));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static boolean isExistingMethodName(Type clazz, String name, VisitorState state) {
|
||||
return ASTHelpers.matchingMethods(state.getName(name), method -> true, clazz, state.getTypes())
|
||||
.findAny()
|
||||
.isPresent();
|
||||
private static boolean isMethodInEnclosingClass(String methodName, VisitorState state) {
|
||||
return state.findEnclosing(ClassTree.class).getMembers().stream()
|
||||
.filter(MethodTree.class::isInstance)
|
||||
.map(MethodTree.class::cast)
|
||||
.map(MethodTree::getName)
|
||||
.map(Name::toString)
|
||||
.anyMatch(methodName::equals);
|
||||
}
|
||||
|
||||
private static boolean isSimpleNameStaticallyImported(String simpleName, VisitorState state) {
|
||||
@@ -160,8 +180,8 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
return source.subSequence(source.lastIndexOf('.') + 1, source.length());
|
||||
}
|
||||
|
||||
private static Optional<String> tryCanonicalizeMethodName(Symbol symbol) {
|
||||
return Optional.of(symbol.getQualifiedName().toString())
|
||||
private static Optional<String> tryCanonicalizeMethodName(MethodTree tree) {
|
||||
return Optional.of(ASTHelpers.getSymbol(tree).getQualifiedName().toString())
|
||||
.filter(name -> name.startsWith(TEST_PREFIX))
|
||||
.map(name -> name.substring(TEST_PREFIX.length()))
|
||||
.filter(not(String::isEmpty))
|
||||
@@ -169,9 +189,17 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
.filter(name -> !Character.isDigit(name.charAt(0)));
|
||||
}
|
||||
|
||||
private static boolean isOverride(MethodTree tree, VisitorState state) {
|
||||
return ASTHelpers.streamSuperMethods(ASTHelpers.getSymbol(tree), state.getTypes())
|
||||
.findAny()
|
||||
.isPresent();
|
||||
// XXX: Move to a `MoreMatchers` utility class.
|
||||
private static Matcher<AnnotationTree> hasMetaAnnotation(String annotationClassName) {
|
||||
TypePredicate typePredicate = hasAnnotation(annotationClassName);
|
||||
return (tree, state) -> {
|
||||
Symbol sym = ASTHelpers.getSymbol(tree);
|
||||
return sym != null && typePredicate.apply(sym.type, state);
|
||||
};
|
||||
}
|
||||
|
||||
// XXX: Move to a `MoreTypePredicates` utility class.
|
||||
private static TypePredicate hasAnnotation(String annotationClassName) {
|
||||
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,8 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
|
||||
import tech.picnic.errorprone.bugpatterns.util.Flags;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
@@ -221,7 +220,7 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
|
||||
private static ImmutableList<String> excludedAnnotations(ErrorProneFlags flags) {
|
||||
Set<String> exclusions = new HashSet<>();
|
||||
exclusions.addAll(Flags.getList(flags, EXCLUDED_ANNOTATIONS_FLAG));
|
||||
flags.getList(EXCLUDED_ANNOTATIONS_FLAG).ifPresent(exclusions::addAll);
|
||||
exclusions.addAll(BLACKLISTED_ANNOTATIONS);
|
||||
return ImmutableList.copyOf(exclusions);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.TypeAnnotations.AnnotationType;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,11 +41,8 @@ public final class NestedOptionals extends BugChecker implements MethodInvocatio
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
Type type = OPTIONAL_OF_OPTIONAL.get(state);
|
||||
if (type == null || !state.getTypes().isSubtype(ASTHelpers.getType(tree), type)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return describeMatch(tree);
|
||||
return state.getTypes().isSubtype(ASTHelpers.getType(tree), OPTIONAL_OF_OPTIONAL.get(state))
|
||||
? describeMatch(tree)
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.bugpatterns.util.Flags;
|
||||
import tech.picnic.errorprone.bugpatterns.util.MethodMatcherFactory;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
@@ -64,8 +63,9 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
public final class RedundantStringConversion extends BugChecker
|
||||
implements BinaryTreeMatcher, CompoundAssignmentTreeMatcher, MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String FLAG_PREFIX = "RedundantStringConversion:";
|
||||
private static final String EXTRA_STRING_CONVERSION_METHODS_FLAG =
|
||||
"RedundantStringConversion:ExtraConversionMethods";
|
||||
FLAG_PREFIX + "ExtraConversionMethods";
|
||||
|
||||
@SuppressWarnings("UnnecessaryLambda")
|
||||
private static final Matcher<ExpressionTree> ANY_EXPR = (t, s) -> true;
|
||||
@@ -374,9 +374,10 @@ public final class RedundantStringConversion extends BugChecker
|
||||
ErrorProneFlags flags) {
|
||||
// XXX: ErrorProneFlags#getList splits by comma, but method signatures may also contain commas.
|
||||
// For this class methods accepting more than one argument are not valid, but still: not nice.
|
||||
return anyOf(
|
||||
WELL_KNOWN_STRING_CONVERSION_METHODS,
|
||||
new MethodMatcherFactory()
|
||||
.create(Flags.getList(flags, EXTRA_STRING_CONVERSION_METHODS_FLAG)));
|
||||
return flags
|
||||
.getList(EXTRA_STRING_CONVERSION_METHODS_FLAG)
|
||||
.map(new MethodMatcherFactory()::create)
|
||||
.map(m -> anyOf(WELL_KNOWN_STRING_CONVERSION_METHODS, m))
|
||||
.orElse(WELL_KNOWN_STRING_CONVERSION_METHODS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
|
||||
@@ -10,72 +9,41 @@ import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.suppliers.Suppliers;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import tech.picnic.errorprone.bugpatterns.util.Flags;
|
||||
|
||||
/** A {@link BugChecker} that flags {@code @RequestParam} parameters with an unsupported type. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"By default, `@RequestParam` does not support `ImmutableCollection` and `ImmutableMap` subtypes",
|
||||
summary = "`@RequestParam` does not support `ImmutableCollection` and `ImmutableMap` subtypes",
|
||||
link = BUG_PATTERNS_BASE_URL + "RequestParamType",
|
||||
linkType = CUSTOM,
|
||||
severity = ERROR,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class RequestParamType extends BugChecker implements VariableTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String SUPPORTED_CUSTOM_TYPES_FLAG = "RequestParamType:SupportedCustomTypes";
|
||||
private static final Matcher<VariableTree> HAS_UNSUPPORTED_REQUEST_PARAM =
|
||||
allOf(
|
||||
annotations(AT_LEAST_ONE, isType("org.springframework.web.bind.annotation.RequestParam")),
|
||||
anyOf(isSubtypeOf(ImmutableCollection.class), isSubtypeOf(ImmutableMap.class)));
|
||||
|
||||
private final Matcher<VariableTree> hasUnsupportedRequestParamType;
|
||||
|
||||
/** Instantiates a default {@link RequestParamType} instance. */
|
||||
public RequestParamType() {
|
||||
this(ErrorProneFlags.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a customized {@link RequestParamType} instance.
|
||||
*
|
||||
* @param flags Any provided command line flags.
|
||||
*/
|
||||
public RequestParamType(ErrorProneFlags flags) {
|
||||
hasUnsupportedRequestParamType = hasUnsupportedRequestParamType(flags);
|
||||
}
|
||||
/** Instantiates a new {@link RequestParamType} instance. */
|
||||
public RequestParamType() {}
|
||||
|
||||
@Override
|
||||
public Description matchVariable(VariableTree tree, VisitorState state) {
|
||||
return hasUnsupportedRequestParamType.matches(tree, state)
|
||||
return HAS_UNSUPPORTED_REQUEST_PARAM.matches(tree, state)
|
||||
? describeMatch(tree)
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private static Matcher<VariableTree> hasUnsupportedRequestParamType(ErrorProneFlags flags) {
|
||||
return allOf(
|
||||
annotations(AT_LEAST_ONE, isType("org.springframework.web.bind.annotation.RequestParam")),
|
||||
anyOf(isSubtypeOf(ImmutableCollection.class), isSubtypeOf(ImmutableMap.class)),
|
||||
not(isSubtypeOfAny(Flags.getList(flags, SUPPORTED_CUSTOM_TYPES_FLAG))));
|
||||
}
|
||||
|
||||
private static Matcher<Tree> isSubtypeOfAny(ImmutableList<String> inclusions) {
|
||||
return anyOf(
|
||||
inclusions.stream()
|
||||
.map(inclusion -> isSubtypeOf(Suppliers.typeFromString(inclusion)))
|
||||
.collect(toImmutableList()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
|
||||
import com.google.errorprone.fixes.Fix;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.AssignmentTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Scope;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags annotations with time attributes that can be written more
|
||||
* concisely.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Simplifies annotations which express an amount of time using a `TimeUnit`",
|
||||
link = BUG_PATTERNS_BASE_URL + "SimplifyTimeAnnotation",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class SimplifyTimeAnnotationCheck extends BugChecker implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final AnnotationAttributeMatcher ARGUMENT_SELECTOR =
|
||||
createAnnotationAttributeMatcher();
|
||||
|
||||
/** Instantiates a new {@link SimplifyTimeAnnotationCheck} instance. */
|
||||
public SimplifyTimeAnnotationCheck() {}
|
||||
|
||||
@Override
|
||||
public Description matchAnnotation(AnnotationTree annotationTree, VisitorState state) {
|
||||
ImmutableList<ExpressionTree> arguments =
|
||||
ARGUMENT_SELECTOR.extractMatchingArguments(annotationTree).collect(toImmutableList());
|
||||
|
||||
if (arguments.isEmpty()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return trySimplification(annotationTree, arguments, state)
|
||||
.map(fix -> describeMatch(annotationTree, fix))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
private static Optional<Fix> trySimplification(
|
||||
AnnotationTree annotation, ImmutableList<ExpressionTree> arguments, VisitorState state) {
|
||||
checkArgument(!arguments.isEmpty());
|
||||
|
||||
AnnotationDescriptor annotationDescriptor =
|
||||
AnnotationDescriptor.from(getAnnotationFqcn(annotation));
|
||||
if (containsAnyAttributeOf(annotation, annotationDescriptor.bannedFields)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ImmutableMap<String, ExpressionTree> indexedAttributes =
|
||||
Maps.uniqueIndex(
|
||||
arguments,
|
||||
expr ->
|
||||
ASTHelpers.getSymbol(((AssignmentTree) expr).getVariable())
|
||||
.getSimpleName()
|
||||
.toString());
|
||||
|
||||
TimeUnit currentTimeUnit =
|
||||
getTimeUnit(annotation, annotationDescriptor.timeUnitField, indexedAttributes);
|
||||
|
||||
ImmutableMap<String, Number> timeValues =
|
||||
annotationDescriptor.timeFields.stream()
|
||||
.map(field -> Map.entry(field, getValue(field, indexedAttributes)))
|
||||
.filter(entry -> entry.getValue().isPresent())
|
||||
.collect(toImmutableMap(Map.Entry::getKey, entry -> entry.getValue().orElseThrow()));
|
||||
|
||||
Map<String, TimeSimplifier.Simplification> simplifications =
|
||||
Maps.transformValues(
|
||||
Maps.filterValues(
|
||||
Maps.transformEntries(
|
||||
timeValues, (field, value) -> trySimplify(value, currentTimeUnit)),
|
||||
Optional::isPresent),
|
||||
Optional::orElseThrow);
|
||||
|
||||
// Some could not be simplified, and since the unit is shared, the others can't either.
|
||||
if (simplifications.size() != timeValues.size()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// The annotation is of the form `@Annotation(v)` or `@Annotation(value = v)`. For the former we
|
||||
// must synthesize the entire annotation, but this is OK for the latter, too.
|
||||
if (indexedAttributes.size() == 1 && simplifications.containsKey("value")) {
|
||||
TimeSimplifier.Simplification simplification = simplifications.get("value");
|
||||
return Optional.of(
|
||||
getImplicitValueAttributeFix(
|
||||
annotation,
|
||||
simplification.value,
|
||||
annotationDescriptor.timeUnitField,
|
||||
simplification.timeUnit,
|
||||
state));
|
||||
}
|
||||
|
||||
// Since each might have a different simplification possible, check the common unit.
|
||||
// Since we only get simplifications iff it's possible, and we check that all can be simplified,
|
||||
// we don't need to check if this equals `currentTimeUnit`.
|
||||
TimeUnit commonUnit =
|
||||
findCommonUnit(
|
||||
ImmutableSet.copyOf(
|
||||
Maps.transformValues(simplifications, simplification -> simplification.timeUnit)
|
||||
.values()));
|
||||
|
||||
return getExplicitAttributesFix(
|
||||
annotation, simplifications, annotationDescriptor.timeUnitField, commonUnit, state);
|
||||
}
|
||||
|
||||
private static boolean containsAnyAttributeOf(
|
||||
AnnotationTree annotation, ImmutableSet<String> attributes) {
|
||||
return annotation.getArguments().stream()
|
||||
.map(
|
||||
expr ->
|
||||
expr.getKind() == Tree.Kind.ASSIGNMENT
|
||||
? ASTHelpers.getSymbol(((AssignmentTree) expr).getVariable())
|
||||
.getSimpleName()
|
||||
.toString()
|
||||
: "value")
|
||||
.anyMatch(attributes::contains);
|
||||
}
|
||||
|
||||
private static Fix getImplicitValueAttributeFix(
|
||||
AnnotationTree annotation,
|
||||
long newValue,
|
||||
String timeUnitField,
|
||||
TimeUnit newTimeUnit,
|
||||
VisitorState state) {
|
||||
String synthesizedAnnotation =
|
||||
SourceCode.treeToString(annotation, state)
|
||||
.replaceFirst(
|
||||
"\\(.+\\)",
|
||||
String.format("(value=%s, %s=%s)", newValue, timeUnitField, newTimeUnit.name()));
|
||||
return SuggestedFix.builder()
|
||||
.replace(annotation, synthesizedAnnotation)
|
||||
.addStaticImport(TimeUnit.class.getName() + '.' + newTimeUnit.name())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Optional<Fix> getExplicitAttributesFix(
|
||||
AnnotationTree annotation,
|
||||
Map<String, TimeSimplifier.Simplification> simplifications,
|
||||
String timeUnitField,
|
||||
TimeUnit newUnit,
|
||||
VisitorState state) {
|
||||
return simplifications.entrySet().stream()
|
||||
.map(
|
||||
simplificationEntry ->
|
||||
SuggestedFixes.updateAnnotationArgumentValues(
|
||||
annotation, state, timeUnitField, ImmutableList.of(newUnit.name()))
|
||||
.merge(
|
||||
SuggestedFixes.updateAnnotationArgumentValues(
|
||||
annotation,
|
||||
state,
|
||||
simplificationEntry.getKey(),
|
||||
ImmutableList.of(
|
||||
String.valueOf(simplificationEntry.getValue().toUnit(newUnit))))))
|
||||
.reduce(SuggestedFix.Builder::merge)
|
||||
.map(builder -> builder.addStaticImport(TimeUnit.class.getName() + '.' + newUnit.name()))
|
||||
.map(SuggestedFix.Builder::build);
|
||||
}
|
||||
|
||||
private static String getAnnotationFqcn(AnnotationTree annotation) {
|
||||
return ASTHelpers.getSymbol(annotation).getQualifiedName().toString();
|
||||
}
|
||||
|
||||
private static Optional<Number> getValue(
|
||||
String field, ImmutableMap<String, ExpressionTree> indexedArguments) {
|
||||
return Optional.ofNullable(indexedArguments.get(field))
|
||||
.filter(AssignmentTree.class::isInstance)
|
||||
.map(AssignmentTree.class::cast)
|
||||
.map(AssignmentTree::getExpression)
|
||||
.map(expr -> ASTHelpers.constValue(expr, Number.class));
|
||||
}
|
||||
|
||||
private static TimeUnit getTimeUnit(
|
||||
AnnotationTree annotation,
|
||||
String field,
|
||||
ImmutableMap<String, ExpressionTree> indexedArguments) {
|
||||
VarSymbol symbol =
|
||||
Optional.ofNullable(indexedArguments.get(field))
|
||||
.map(
|
||||
argumentTree ->
|
||||
(VarSymbol)
|
||||
ASTHelpers.getSymbol(((AssignmentTree) argumentTree).getExpression()))
|
||||
.orElseGet(() -> getDefaultTimeUnit(annotation, field));
|
||||
return TimeUnit.valueOf(symbol.getQualifiedName().toString());
|
||||
}
|
||||
|
||||
private static VarSymbol getDefaultTimeUnit(AnnotationTree annotation, String argument) {
|
||||
Scope scope = ASTHelpers.getSymbol(annotation).members();
|
||||
MethodSymbol argumentSymbol =
|
||||
(MethodSymbol)
|
||||
Iterables.getOnlyElement(
|
||||
ASTHelpers.scope(scope)
|
||||
.getSymbols(symbol -> symbol.getQualifiedName().contentEquals(argument)));
|
||||
return (VarSymbol)
|
||||
requireNonNull(argumentSymbol.getDefaultValue(), "Default value missing").getValue();
|
||||
}
|
||||
|
||||
private static AnnotationAttributeMatcher createAnnotationAttributeMatcher() {
|
||||
ImmutableList<String> toMatch =
|
||||
Arrays.stream(AnnotationDescriptor.values())
|
||||
.flatMap(
|
||||
annotation ->
|
||||
annotation.timeFields.stream().map(field -> annotation.fqcn + '#' + field))
|
||||
.collect(toImmutableList());
|
||||
return AnnotationAttributeMatcher.create(Optional.of(toMatch), ImmutableList.of());
|
||||
}
|
||||
|
||||
private static Optional<TimeSimplifier.Simplification> trySimplify(Number value, TimeUnit unit) {
|
||||
checkArgument(
|
||||
value instanceof Integer || value instanceof Long,
|
||||
"Only time expressed as an integer or long can be simplified");
|
||||
return TimeSimplifier.simplify(value.longValue(), unit);
|
||||
}
|
||||
|
||||
private static TimeUnit findCommonUnit(ImmutableSet<TimeUnit> units) {
|
||||
return ImmutableSortedSet.copyOf(units).first();
|
||||
}
|
||||
|
||||
private enum AnnotationDescriptor {
|
||||
JUNIT_TIMEOUT("org.junit.jupiter.api.Timeout", ImmutableSet.of("value"), "unit"),
|
||||
SPRING_SCHEDULED(
|
||||
"org.springframework.scheduling.annotation.Scheduled",
|
||||
ImmutableSet.of("fixedDelay", "fixedRate", "initialDelay"),
|
||||
"timeUnit",
|
||||
ImmutableSet.of("fixedDelayString", "fixedRateString", "initialDelayString"));
|
||||
|
||||
/** The fully-qualified class name of the annotation to simplify. */
|
||||
private final String fqcn;
|
||||
/** The attributes containing a value of time. */
|
||||
private final ImmutableSet<String> timeFields;
|
||||
/** The attribute containing the time unit. */
|
||||
private final String timeUnitField;
|
||||
/** The set of attributes that cause the check to back off. */
|
||||
private final ImmutableSet<String> bannedFields;
|
||||
|
||||
AnnotationDescriptor(String fqcn, ImmutableSet<String> timeFields, String timeUnitField) {
|
||||
this(fqcn, timeFields, timeUnitField, ImmutableSet.of());
|
||||
}
|
||||
|
||||
AnnotationDescriptor(
|
||||
String fqcn,
|
||||
ImmutableSet<String> timeFields,
|
||||
String timeUnitField,
|
||||
ImmutableSet<String> bannedFields) {
|
||||
this.fqcn = fqcn;
|
||||
this.timeFields = timeFields;
|
||||
this.timeUnitField = timeUnitField;
|
||||
this.bannedFields = bannedFields;
|
||||
}
|
||||
|
||||
public static AnnotationDescriptor from(String fqcn) {
|
||||
return Arrays.stream(values())
|
||||
.filter(annotation -> annotation.fqcn.equals(fqcn))
|
||||
.findFirst()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format(
|
||||
"Unknown enum constant: %s.%s",
|
||||
AnnotationDescriptor.class.getName(), fqcn)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Utility class to help simplify time expressions. */
|
||||
private static final class TimeSimplifier {
|
||||
private static final ImmutableSortedSet<TimeUnit> TIME_UNITS =
|
||||
ImmutableSortedSet.copyOf(TimeUnit.values());
|
||||
|
||||
/**
|
||||
* Returns a {@link Simplification} (iff possible) that describes how the {@code originalValue}
|
||||
* and {@code originalUnit} can be simplified using a larger {@link TimeUnit}.
|
||||
*/
|
||||
static Optional<Simplification> simplify(long originalValue, TimeUnit originalUnit) {
|
||||
return descendingLargerUnits(originalUnit).stream()
|
||||
.flatMap(unit -> trySimplify(originalValue, originalUnit, unit))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private static Stream<Simplification> trySimplify(
|
||||
long originalValue, TimeUnit originalUnit, TimeUnit unit) {
|
||||
long converted = unit.convert(originalValue, originalUnit);
|
||||
// Check whether we lose any precision by checking whether we can convert back.
|
||||
return originalValue == originalUnit.convert(converted, unit)
|
||||
? Stream.of(new Simplification(converted, unit))
|
||||
: Stream.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all time units that represent a larger amount of time than {@code unit}, in
|
||||
* descending order.
|
||||
*/
|
||||
private static ImmutableSortedSet<TimeUnit> descendingLargerUnits(TimeUnit unit) {
|
||||
return TIME_UNITS.tailSet(unit, /* inclusive= */ false).descendingSet();
|
||||
}
|
||||
|
||||
/** Represents a simplification in terms of the new value and new unit. */
|
||||
private static final class Simplification {
|
||||
private final long value;
|
||||
private final TimeUnit timeUnit;
|
||||
|
||||
Simplification(long value, TimeUnit timeUnit) {
|
||||
this.value = value;
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the value with the unit represented by this simplification to an equivalent value
|
||||
* in the given {@code unit}.
|
||||
*/
|
||||
public long toUnit(TimeUnit unit) {
|
||||
return unit.convert(value, timeUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
|
||||
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
|
||||
import static com.sun.tools.javac.parser.Tokens.TokenKind.RPAREN;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.fixes.Fix;
|
||||
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.google.errorprone.util.ErrorProneTokens;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.util.Position;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags calls to {@link String#toLowerCase()} and {@link
|
||||
* String#toUpperCase()}, as these methods implicitly rely on the environment's default locale.
|
||||
*/
|
||||
// XXX: Also flag `String::toLowerCase` and `String::toUpperCase` method references. For these cases
|
||||
// the suggested fix should introduce a lambda expression with a parameter of which the name does
|
||||
// not coincide with the name of an existing variable name. Such functionality should likely be
|
||||
// introduced in a utility class.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Specify a `Locale` when calling `String#to{Lower,Upper}Case`",
|
||||
link = BUG_PATTERNS_BASE_URL + "StringCaseLocaleUsage",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class StringCaseLocaleUsage extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> DEFAULT_LOCALE_CASE_CONVERSION =
|
||||
instanceMethod()
|
||||
.onExactClass(String.class.getName())
|
||||
.namedAnyOf("toLowerCase", "toUpperCase")
|
||||
.withNoParameters();
|
||||
|
||||
/** Instantiates a new {@link StringCaseLocaleUsage} instance. */
|
||||
public StringCaseLocaleUsage() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (!DEFAULT_LOCALE_CASE_CONVERSION.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
int closingParenPosition = getClosingParenPosition(tree, state);
|
||||
if (closingParenPosition == Position.NOPOS) {
|
||||
return describeMatch(tree);
|
||||
}
|
||||
|
||||
return buildDescription(tree)
|
||||
.addFix(suggestLocale(closingParenPosition, "Locale.ROOT"))
|
||||
.addFix(suggestLocale(closingParenPosition, "Locale.getDefault()"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Fix suggestLocale(int insertPosition, String locale) {
|
||||
return SuggestedFix.builder()
|
||||
.addImport("java.util.Locale")
|
||||
.replace(insertPosition, insertPosition, locale)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static int getClosingParenPosition(MethodInvocationTree tree, VisitorState state) {
|
||||
int startPosition = ASTHelpers.getStartPosition(tree);
|
||||
if (startPosition == Position.NOPOS) {
|
||||
return Position.NOPOS;
|
||||
}
|
||||
|
||||
return Streams.findLast(
|
||||
ErrorProneTokens.getTokens(SourceCode.treeToString(tree, state), state.context).stream()
|
||||
.filter(t -> t.kind() == RPAREN))
|
||||
.map(token -> startPosition + token.pos())
|
||||
.orElse(Position.NOPOS);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import com.sun.tools.javac.util.Convert;
|
||||
import java.util.Formattable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Picnic Error Prone Contrib checks. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.jspecify.nullness.NullMarked
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
|
||||
/** Helper methods for working with {@link ErrorProneFlags}. */
|
||||
public final class Flags {
|
||||
private Flags() {}
|
||||
|
||||
/**
|
||||
* Returns the list of (comma-separated) arguments passed using the given Error Prone flag.
|
||||
*
|
||||
* @param errorProneFlags The full set of flags provided.
|
||||
* @param name The name of the flag of interest.
|
||||
* @return A non-{@code null} list of provided arguments; this list is empty if the flag was not
|
||||
* provided, or if the flag's value is the empty string.
|
||||
*/
|
||||
public static ImmutableList<String> getList(ErrorProneFlags errorProneFlags, String name) {
|
||||
return errorProneFlags
|
||||
.getList(name)
|
||||
.map(ImmutableList::copyOf)
|
||||
.filter(flags -> !flags.equals(ImmutableList.of("")))
|
||||
.orElseGet(ImmutableList::of);
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/** Utility class that can be used to identify reserved keywords of the Java language. */
|
||||
// XXX: This class is no longer only about keywords. Consider changing its name and class-level
|
||||
// documentation.
|
||||
public final class JavaKeywords {
|
||||
/**
|
||||
* Enumeration of boolean and null literals.
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.10.3">JDK 17
|
||||
* JLS section 3.10.3: Boolean Literals</a>
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.10.8">JDK 17
|
||||
* JLS section 3.10.8: The Null Literal</a>
|
||||
*/
|
||||
private static final ImmutableSet<String> BOOLEAN_AND_NULL_LITERALS =
|
||||
ImmutableSet.of("true", "false", "null");
|
||||
/**
|
||||
* List of all reserved keywords in the Java language.
|
||||
*
|
||||
@@ -76,6 +64,7 @@ public final class JavaKeywords {
|
||||
"void",
|
||||
"volatile",
|
||||
"while");
|
||||
|
||||
/**
|
||||
* List of all contextual keywords in the Java language.
|
||||
*
|
||||
@@ -100,28 +89,13 @@ public final class JavaKeywords {
|
||||
"var",
|
||||
"with",
|
||||
"yield");
|
||||
|
||||
/** List of all keywords in the Java language. */
|
||||
private static final ImmutableSet<String> ALL_KEYWORDS =
|
||||
Sets.union(RESERVED_KEYWORDS, CONTEXTUAL_KEYWORDS).immutableCopy();
|
||||
|
||||
private JavaKeywords() {}
|
||||
|
||||
/**
|
||||
* Tells whether the given string is a valid identifier in the Java language.
|
||||
*
|
||||
* @param str The string of interest.
|
||||
* @return {@code true} if the given string is a valid identifier in the Java language.
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.8">JDK 17 JLS
|
||||
* section 3.8: Identifiers</a>
|
||||
*/
|
||||
public static boolean isValidIdentifier(String str) {
|
||||
return !str.isEmpty()
|
||||
&& !isReservedKeyword(str)
|
||||
&& !BOOLEAN_AND_NULL_LITERALS.contains(str)
|
||||
&& Character.isJavaIdentifierStart(str.codePointAt(0))
|
||||
&& str.codePoints().skip(1).allMatch(Character::isUnicodeIdentifierPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given string is a reserved keyword in the Java language.
|
||||
*
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
|
||||
/**
|
||||
* A collection of helper methods for working with the AST.
|
||||
*
|
||||
* <p>These methods are additions to the ones found in {@link
|
||||
* com.google.errorprone.util.ASTHelpers}.
|
||||
*/
|
||||
public final class MoreASTHelpers {
|
||||
private MoreASTHelpers() {}
|
||||
|
||||
/**
|
||||
* Finds methods with the specified name in given the {@link VisitorState}'s current enclosing
|
||||
* class.
|
||||
*
|
||||
* @param methodName The method name to search for.
|
||||
* @param state The {@link VisitorState} from which to derive the enclosing class of interest.
|
||||
* @return The {@link MethodTree}s of the methods with the given name in the enclosing class.
|
||||
*/
|
||||
public static ImmutableList<MethodTree> findMethods(CharSequence methodName, VisitorState state) {
|
||||
ClassTree clazz = state.findEnclosing(ClassTree.class);
|
||||
checkArgument(clazz != null, "Visited node is not enclosed by a class");
|
||||
return clazz.getMembers().stream()
|
||||
.filter(MethodTree.class::isInstance)
|
||||
.map(MethodTree.class::cast)
|
||||
.filter(method -> method.getName().contentEquals(methodName))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether there are any methods with the specified name in given the {@link
|
||||
* VisitorState}'s current enclosing class.
|
||||
*
|
||||
* @param methodName The method name to search for.
|
||||
* @param state The {@link VisitorState} from which to derive the enclosing class of interest.
|
||||
* @return Whether there are any methods with the given name in the enclosing class.
|
||||
*/
|
||||
public static boolean methodExistsInEnclosingClass(CharSequence methodName, VisitorState state) {
|
||||
return !findMethods(methodName, state).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
|
||||
import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.hasMetaAnnotation;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.matchers.AnnotationMatcherUtils;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewArrayTree;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A collection of JUnit-specific helper methods and {@link Matcher}s.
|
||||
*
|
||||
* <p>These constants and methods are additions to the ones found in {@link
|
||||
* com.google.errorprone.matchers.JUnitMatchers}.
|
||||
*/
|
||||
public final class MoreJUnitMatchers {
|
||||
/** Matches JUnit Jupiter test methods. */
|
||||
public static final MultiMatcher<MethodTree, AnnotationTree> TEST_METHOD =
|
||||
annotations(
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType("org.junit.jupiter.api.Test"),
|
||||
hasMetaAnnotation("org.junit.jupiter.api.TestTemplate")));
|
||||
/** Matches JUnit Jupiter setup and teardown methods. */
|
||||
public static final MultiMatcher<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
|
||||
annotations(
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType("org.junit.jupiter.api.AfterAll"),
|
||||
isType("org.junit.jupiter.api.AfterEach"),
|
||||
isType("org.junit.jupiter.api.BeforeAll"),
|
||||
isType("org.junit.jupiter.api.BeforeEach")));
|
||||
/**
|
||||
* Matches methods that have a {@link org.junit.jupiter.params.provider.MethodSource} annotation.
|
||||
*/
|
||||
public static final MultiMatcher<MethodTree, AnnotationTree> HAS_METHOD_SOURCE =
|
||||
annotations(AT_LEAST_ONE, isType("org.junit.jupiter.params.provider.MethodSource"));
|
||||
|
||||
private MoreJUnitMatchers() {}
|
||||
|
||||
/**
|
||||
* Returns the names of the JUnit value factory methods specified by the given {@link
|
||||
* org.junit.jupiter.params.provider.MethodSource} annotation.
|
||||
*
|
||||
* @param methodSourceAnnotation The annotation from which to extract value factory method names.
|
||||
* @return One or more value factory names.
|
||||
*/
|
||||
static ImmutableSet<String> getMethodSourceFactoryNames(
|
||||
AnnotationTree methodSourceAnnotation, MethodTree method) {
|
||||
String methodName = method.getName().toString();
|
||||
ExpressionTree value = AnnotationMatcherUtils.getArgument(methodSourceAnnotation, "value");
|
||||
|
||||
if (!(value instanceof NewArrayTree)) {
|
||||
return ImmutableSet.of(toMethodSourceFactoryName(value, methodName));
|
||||
}
|
||||
|
||||
return ((NewArrayTree) value)
|
||||
.getInitializers().stream()
|
||||
.map(name -> toMethodSourceFactoryName(name, methodName))
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
private static String toMethodSourceFactoryName(
|
||||
@Nullable ExpressionTree tree, String annotatedMethodName) {
|
||||
return requireNonNullElse(
|
||||
Strings.emptyToNull(ASTHelpers.constValue(tree, String.class)), annotatedMethodName);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import com.google.errorprone.predicates.TypePredicate;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
|
||||
/**
|
||||
* A collection of general-purpose {@link Matcher}s.
|
||||
*
|
||||
* <p>These methods are additions to the ones found in {@link Matchers}.
|
||||
*/
|
||||
public final class MoreMatchers {
|
||||
private MoreMatchers() {}
|
||||
|
||||
/**
|
||||
* Returns a {@link Matcher} that determines whether a given {@link AnnotationTree} has a
|
||||
* meta-annotation of the specified type.
|
||||
*
|
||||
* @param <T> The type of tree to match against.
|
||||
* @param annotationType The binary type name of the annotation (e.g.
|
||||
* "org.jspecify.annotations.Nullable", or "some.package.OuterClassName$InnerClassName")
|
||||
* @return A {@link Matcher} that matches trees with the specified meta-annotation.
|
||||
*/
|
||||
public static <T extends AnnotationTree> Matcher<T> hasMetaAnnotation(String annotationType) {
|
||||
TypePredicate typePredicate = hasAnnotation(annotationType);
|
||||
return (tree, state) -> {
|
||||
Symbol sym = ASTHelpers.getSymbol(tree);
|
||||
return sym != null && typePredicate.apply(sym.type, state);
|
||||
};
|
||||
}
|
||||
|
||||
// XXX: Consider moving to a `MoreTypePredicates` utility class.
|
||||
private static TypePredicate hasAnnotation(String annotationClassName) {
|
||||
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,14 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.sun.tools.javac.util.Position.NOPOS;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
|
||||
/**
|
||||
* A collection of Error Prone utility methods for dealing with the source code representation of
|
||||
* AST nodes.
|
||||
*/
|
||||
// XXX: Can we locate this code in a better place? Maybe contribute it upstream?
|
||||
public final class SourceCode {
|
||||
/** The complement of {@link CharMatcher#whitespace()}. */
|
||||
private static final CharMatcher NON_WHITESPACE_MATCHER = CharMatcher.whitespace().negate();
|
||||
|
||||
private SourceCode() {}
|
||||
|
||||
/**
|
||||
@@ -31,32 +24,4 @@ public final class SourceCode {
|
||||
String src = state.getSourceForNode(tree);
|
||||
return src != null ? src : tree.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SuggestedFix} for the deletion of the given {@link Tree}, including any
|
||||
* whitespace that follows it.
|
||||
*
|
||||
* <p>Removing trailing whitespace may prevent the introduction of an empty line at the start of a
|
||||
* code block; such empty lines are not removed when formatting the code using Google Java Format.
|
||||
*
|
||||
* @param tree The AST node of interest.
|
||||
* @param state A {@link VisitorState} describing the context in which the given {@link Tree} is
|
||||
* found.
|
||||
* @return A non-{@code null} {@link SuggestedFix} similar to one produced by {@link
|
||||
* SuggestedFix#delete(Tree)}.
|
||||
*/
|
||||
public static SuggestedFix deleteWithTrailingWhitespace(Tree tree, VisitorState state) {
|
||||
CharSequence sourceCode = state.getSourceCode();
|
||||
int endPos = state.getEndPosition(tree);
|
||||
if (sourceCode == null || endPos == NOPOS) {
|
||||
/* We can't identify the trailing whitespace; delete just the tree. */
|
||||
return SuggestedFix.delete(tree);
|
||||
}
|
||||
|
||||
int whitespaceEndPos = NON_WHITESPACE_MATCHER.indexIn(sourceCode, endPos);
|
||||
return SuggestedFix.replace(
|
||||
((DiagnosticPosition) tree).getStartPosition(),
|
||||
whitespaceEndPos == -1 ? sourceCode.length() : whitespaceEndPos,
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Auxiliary utilities for use by Error Prone checks. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.jspecify.nullness.NullMarked
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
@@ -1,148 +1,16 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.ImmutableSortedMultiset;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@OnlineDocumentation
|
||||
final class AssertJMapRules {
|
||||
private AssertJMapRules() {}
|
||||
|
||||
// XXX: Reduce boilerplate using a `Matcher` that identifies "empty" instances.
|
||||
static final class AbstractMapAssertIsEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
void before(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
Refaster.anyOf(
|
||||
mapAssert.containsExactlyEntriesOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.hasSameSizeAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.isEqualTo(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.containsOnlyKeys(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
mapAssert.containsExactly(),
|
||||
mapAssert.containsOnly(),
|
||||
mapAssert.containsOnlyKeys());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
mapAssert.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapIsEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
void before(Map<K, V> map) {
|
||||
Refaster.anyOf(
|
||||
assertThat(map).hasSize(0),
|
||||
assertThat(map.isEmpty()).isTrue(),
|
||||
assertThat(map.size()).isEqualTo(0L),
|
||||
assertThat(map.size()).isNotPositive());
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before2(Map<K, V> map) {
|
||||
assertThat(Refaster.anyOf(map.keySet(), map.values(), map.entrySet())).isEmpty();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Map<K, V> map) {
|
||||
assertThat(map).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AbstractMapAssertIsNotEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
return mapAssert.isNotEqualTo(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
return mapAssert.isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapIsNotEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Map<K, V> map) {
|
||||
return Refaster.anyOf(
|
||||
assertThat(map.isEmpty()).isFalse(),
|
||||
assertThat(map.size()).isNotEqualTo(0),
|
||||
assertThat(map.size()).isPositive(),
|
||||
assertThat(Refaster.anyOf(map.keySet(), map.values(), map.entrySet())).isNotEmpty());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map) {
|
||||
return assertThat(map).isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AbstractMapAssertContainsExactlyInAnyOrderEntriesOf<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
@@ -166,83 +34,4 @@ final class AssertJMapRules {
|
||||
return mapAssert.containsExactlyEntriesOf(ImmutableMap.of(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapHasSize<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Map<K, V> map, int length) {
|
||||
return Refaster.anyOf(
|
||||
assertThat(map.size()).isEqualTo(length),
|
||||
assertThat(Refaster.anyOf(map.keySet(), map.values(), map.entrySet())).hasSize(length));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, int length) {
|
||||
return assertThat(map).hasSize(length);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AbstractMapAssertHasSameSizeAs<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
return mapAssert.hasSize(map.size());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
return mapAssert.hasSameSizeAs(map);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapContainsKey<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Map<K, V> map, K key) {
|
||||
return assertThat(map.containsKey(key)).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, K key) {
|
||||
return assertThat(map).containsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapDoesNotContainKey<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Map<K, V> map, K key) {
|
||||
return assertThat(map.containsKey(key)).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, K key) {
|
||||
return assertThat(map).doesNotContainKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapContainsValue<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Map<K, V> map, V value) {
|
||||
return assertThat(map.containsValue(value)).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, V value) {
|
||||
return assertThat(map).containsValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapDoesNotContainValue<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Map<K, V> map, V value) {
|
||||
return assertThat(map.containsValue(value)).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, V value) {
|
||||
return assertThat(map).doesNotContainValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ final class AssertJOptionalRules {
|
||||
|
||||
static final class AssertThatOptional<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NullAway")
|
||||
ObjectAssert<T> before(Optional<T> optional) {
|
||||
return assertThat(optional.orElseThrow());
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.ImmutableSortedMultiset;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -19,7 +22,9 @@ import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -27,16 +32,19 @@ import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
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;
|
||||
import org.assertj.core.api.AbstractLongAssert;
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.api.IterableAssert;
|
||||
import org.assertj.core.api.ListAssert;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
@@ -558,8 +566,173 @@ final class AssertJRules {
|
||||
// Map
|
||||
//
|
||||
|
||||
// XXX: To match in all cases there'll need to be a `@BeforeTemplate` variant for each
|
||||
// `assertThat` overload. Consider defining a `BugChecker` instead.
|
||||
static final class AssertThatMapIsEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
void before(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
Refaster.anyOf(
|
||||
mapAssert.containsExactlyEntriesOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.hasSameSizeAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.isEqualTo(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.containsOnlyKeys(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
mapAssert.containsExactly(),
|
||||
mapAssert.containsOnly(),
|
||||
mapAssert.containsOnlyKeys());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
mapAssert.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Find a better name.
|
||||
static final class AssertThatMapIsEmpty2<K, V> {
|
||||
@BeforeTemplate
|
||||
void before(Map<K, V> map) {
|
||||
Refaster.anyOf(
|
||||
assertThat(map).hasSize(0),
|
||||
assertThat(map.isEmpty()).isTrue(),
|
||||
assertThat(map.size()).isEqualTo(0L),
|
||||
assertThat(map.size()).isNotPositive());
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before2(Map<K, V> map) {
|
||||
assertThat(Refaster.anyOf(map.keySet(), map.values())).isEmpty();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Map<K, V> map) {
|
||||
assertThat(map).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapIsNotEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
return mapAssert.isNotEqualTo(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
return mapAssert.isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Find a better name.
|
||||
static final class AssertThatMapIsNotEmpty2<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Map<K, V> map) {
|
||||
return Refaster.anyOf(
|
||||
assertThat(map.isEmpty()).isFalse(),
|
||||
assertThat(map.size()).isNotEqualTo(0),
|
||||
assertThat(map.size()).isPositive(),
|
||||
assertThat(Refaster.anyOf(map.keySet(), map.values())).isNotEmpty());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map) {
|
||||
return assertThat(map).isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapHasSize<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Map<K, V> map, int length) {
|
||||
return Refaster.anyOf(
|
||||
assertThat(map.size()).isEqualTo(length),
|
||||
assertThat(Refaster.anyOf(map.keySet(), map.values())).hasSize(length));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, int length) {
|
||||
return assertThat(map).hasSize(length);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapsHaveSameSize<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(Map<K, V> map1, Map<K, V> map2) {
|
||||
return assertThat(map1)
|
||||
.hasSize(Refaster.anyOf(map2.size(), map2.keySet().size(), map2.values().size()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map1, Map<K, V> map2) {
|
||||
return assertThat(map1).hasSameSizeAs(map2);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Should also add a rule (elsewhere) to simplify `map.keySet().contains(key)`.
|
||||
static final class AssertThatMapContainsKey<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Map<K, V> map, K key) {
|
||||
return assertThat(map.containsKey(key)).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, K key) {
|
||||
return assertThat(map).containsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapDoesNotContainKey<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(Map<K, V> map, K key) {
|
||||
return assertThat(map.containsKey(key)).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, K key) {
|
||||
return assertThat(map).doesNotContainKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMapContainsEntry<K, V> {
|
||||
@BeforeTemplate
|
||||
ObjectAssert<?> before(Map<K, V> map, K key, V value) {
|
||||
|
||||
@@ -19,12 +19,15 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
@@ -70,6 +73,32 @@ final class AssortedRules {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: We could add a rule for `new EnumMap(Map<K, ? extends V> m)`, but that constructor does
|
||||
// not allow an empty non-EnumMap to be provided.
|
||||
static final class CreateEnumMap<K extends Enum<K>, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Map<K, V> after() {
|
||||
return new EnumMap<>(Refaster.<K>clazz());
|
||||
}
|
||||
}
|
||||
|
||||
static final class MapGetOrNull<K, V, L> {
|
||||
@BeforeTemplate
|
||||
@Nullable V before(Map<K, V> map, L key) {
|
||||
return map.getOrDefault(key, null);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@Nullable V after(Map<K, V> map, L key) {
|
||||
return map.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link Sets#toImmutableEnumSet()} when possible, as it is more efficient than {@link
|
||||
* ImmutableSet#toImmutableSet()} and produces a more compact object.
|
||||
@@ -103,8 +132,7 @@ final class AssortedRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@Nullable
|
||||
T after(Iterator<T> iterator, T defaultValue) {
|
||||
@Nullable T after(Iterator<T> iterator, T defaultValue) {
|
||||
return Iterators.getNext(iterator, defaultValue);
|
||||
}
|
||||
}
|
||||
@@ -196,6 +224,32 @@ final class AssortedRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily use {@link Map#entrySet()}. */
|
||||
static final class MapKeyStream<K, V> {
|
||||
@BeforeTemplate
|
||||
Stream<K> before(Map<K, V> map) {
|
||||
return map.entrySet().stream().map(Map.Entry::getKey);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<K> after(Map<K, V> map) {
|
||||
return map.keySet().stream();
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily use {@link Map#entrySet()}. */
|
||||
static final class MapValueStream<K, V> {
|
||||
@BeforeTemplate
|
||||
Stream<V> before(Map<K, V> map) {
|
||||
return map.entrySet().stream().map(Map.Entry::getValue);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<V> after(Map<K, V> map) {
|
||||
return map.values().stream();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Splitter#splitToStream(CharSequence)} over less efficient alternatives. */
|
||||
static final class SplitToStream {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -50,18 +50,17 @@ final class BigDecimalRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link BigDecimal#valueOf(double)} over the associated constructor. */
|
||||
// XXX: Ideally we also rewrite `new BigDecimal("<some-integer-value>")` in cases where the
|
||||
// specified number can be represented as an `int` or `long`, but that requires a custom
|
||||
// `BugChecker`.
|
||||
static final class BigDecimalValueOf {
|
||||
/** Prefer {@link BigDecimal#valueOf(long)} over the associated constructor. */
|
||||
// XXX: Ideally we'd also rewrite `BigDecimal.valueOf("<some-integer-value>")`, but it doesn't
|
||||
// appear that's currently possible with Error Prone.
|
||||
static final class BigDecimalFactoryMethod {
|
||||
@BeforeTemplate
|
||||
BigDecimal before(double value) {
|
||||
BigDecimal before(long value) {
|
||||
return new BigDecimal(value);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
BigDecimal after(double value) {
|
||||
BigDecimal after(long value) {
|
||||
return BigDecimal.valueOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
@@ -405,19 +404,6 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collection#forEach(Consumer)} over more contrived alternatives. */
|
||||
static final class CollectionForEach<T> {
|
||||
@BeforeTemplate
|
||||
void before(Collection<T> collection, Consumer<? super T> consumer) {
|
||||
collection.stream().forEach(consumer);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(Collection<T> collection, Consumer<? super T> consumer) {
|
||||
collection.forEach(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: collection.stream().noneMatch(e -> e.equals(other))
|
||||
// ^ This is !collection.contains(other). Do we already rewrite variations on this?
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -25,7 +24,6 @@ import java.util.function.Function;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Comparator}s. */
|
||||
@@ -39,10 +37,7 @@ final class ComparatorRules {
|
||||
@BeforeTemplate
|
||||
Comparator<T> before() {
|
||||
return Refaster.anyOf(
|
||||
T::compareTo,
|
||||
comparing(Refaster.anyOf(identity(), v -> v)),
|
||||
Collections.<T>reverseOrder(reverseOrder()),
|
||||
Comparator.<T>reverseOrder().reversed());
|
||||
comparing(Refaster.anyOf(identity(), v -> v)), Comparator.<T>reverseOrder().reversed());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -56,15 +51,11 @@ final class ComparatorRules {
|
||||
static final class ReverseOrder<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
Comparator<T> before() {
|
||||
return Refaster.anyOf(
|
||||
Collections.reverseOrder(),
|
||||
Collections.<T>reverseOrder(naturalOrder()),
|
||||
Comparator.<T>naturalOrder().reversed());
|
||||
return Comparator.<T>naturalOrder().reversed();
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` if/when
|
||||
// https://github.com/google/error-prone/pull/3584 is merged and released.
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
Comparator<T> after() {
|
||||
return reverseOrder();
|
||||
}
|
||||
@@ -198,54 +189,15 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Comparable#compareTo(Object)}} over more verbose alternatives. */
|
||||
static final class CompareTo<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
int before(T value1, T value2) {
|
||||
return Refaster.anyOf(
|
||||
Comparator.<T>naturalOrder().compare(value1, value2),
|
||||
Comparator.<T>reverseOrder().compare(value2, value1));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(T value1, T value2) {
|
||||
return value1.compareTo(value2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MinOfVarargs<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("StreamOfArray" /* In practice individual values are provided. */)
|
||||
T before(@Repeated T value, Comparator<T> cmp) {
|
||||
return Stream.of(Refaster.asVarargs(value)).min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(@Repeated T value, Comparator<T> cmp) {
|
||||
return Collections.min(Arrays.asList(value), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Comparators#min(Comparable, Comparable)}} over more verbose alternatives. */
|
||||
static final class MinOfPairNaturalOrder<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
T before(T value1, T value2) {
|
||||
return Refaster.anyOf(
|
||||
value1.compareTo(value2) <= 0 ? value1 : value2,
|
||||
value1.compareTo(value2) > 0 ? value2 : value1,
|
||||
value2.compareTo(value1) < 0 ? value2 : value1,
|
||||
value2.compareTo(value1) >= 0 ? value1 : value2,
|
||||
Comparators.min(value1, value2, naturalOrder()),
|
||||
Comparators.max(value1, value2, reverseOrder()),
|
||||
Collections.min(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2))));
|
||||
return Collections.min(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -260,17 +212,12 @@ final class ComparatorRules {
|
||||
static final class MinOfPairCustomOrder<T> {
|
||||
@BeforeTemplate
|
||||
T before(T value1, T value2, Comparator<T> cmp) {
|
||||
return Refaster.anyOf(
|
||||
cmp.compare(value1, value2) <= 0 ? value1 : value2,
|
||||
cmp.compare(value1, value2) > 0 ? value2 : value1,
|
||||
cmp.compare(value2, value1) < 0 ? value2 : value1,
|
||||
cmp.compare(value2, value1) >= 0 ? value1 : value2,
|
||||
Collections.min(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2)),
|
||||
cmp));
|
||||
return Collections.min(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2)),
|
||||
cmp);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -279,39 +226,15 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MaxOfVarargs<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("StreamOfArray" /* In practice individual values are provided. */)
|
||||
T before(@Repeated T value, Comparator<T> cmp) {
|
||||
return Stream.of(Refaster.asVarargs(value)).max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(@Repeated T value, Comparator<T> cmp) {
|
||||
return Collections.max(Arrays.asList(value), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Comparators#max(Comparable, Comparable)}} over more verbose alternatives. */
|
||||
static final class MaxOfPairNaturalOrder<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
T before(T value1, T value2) {
|
||||
return Refaster.anyOf(
|
||||
value1.compareTo(value2) >= 0 ? value1 : value2,
|
||||
value1.compareTo(value2) < 0 ? value2 : value1,
|
||||
value2.compareTo(value1) > 0 ? value2 : value1,
|
||||
value2.compareTo(value1) <= 0 ? value1 : value2,
|
||||
Comparators.max(value1, value2, naturalOrder()),
|
||||
Comparators.min(value1, value2, reverseOrder()),
|
||||
Collections.max(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2))));
|
||||
return Collections.max(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -326,17 +249,12 @@ final class ComparatorRules {
|
||||
static final class MaxOfPairCustomOrder<T> {
|
||||
@BeforeTemplate
|
||||
T before(T value1, T value2, Comparator<T> cmp) {
|
||||
return Refaster.anyOf(
|
||||
cmp.compare(value1, value2) >= 0 ? value1 : value2,
|
||||
cmp.compare(value1, value2) < 0 ? value2 : value1,
|
||||
cmp.compare(value2, value1) > 0 ? value2 : value1,
|
||||
cmp.compare(value2, value1) <= 0 ? value1 : value2,
|
||||
Collections.max(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2)),
|
||||
cmp));
|
||||
return Collections.max(
|
||||
Refaster.anyOf(
|
||||
Arrays.asList(value1, value2),
|
||||
ImmutableList.of(value1, value2),
|
||||
ImmutableSet.of(value1, value2)),
|
||||
cmp);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -141,22 +141,6 @@ final class DoubleStreamRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link DoubleStream#filter(DoublePredicate)} before {@link DoubleStream#sorted()} to
|
||||
* reduce the number of elements to sort.
|
||||
*/
|
||||
static final class DoubleStreamFilterSorted {
|
||||
@BeforeTemplate
|
||||
DoubleStream before(DoubleStream stream, DoublePredicate predicate) {
|
||||
return stream.sorted().filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
DoubleStream after(DoubleStream stream, DoublePredicate predicate) {
|
||||
return stream.filter(predicate).sorted();
|
||||
}
|
||||
}
|
||||
|
||||
/** In order to test whether a stream has any element, simply try to find one. */
|
||||
static final class DoubleStreamIsEmpty {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -154,22 +154,6 @@ final class IntStreamRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link IntStream#filter(IntPredicate)} before {@link IntStream#sorted()} to reduce the
|
||||
* number of elements to sort.
|
||||
*/
|
||||
static final class IntStreamFilterSorted {
|
||||
@BeforeTemplate
|
||||
IntStream before(IntStream stream, IntPredicate predicate) {
|
||||
return stream.sorted().filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
IntStream after(IntStream stream, IntPredicate predicate) {
|
||||
return stream.filter(predicate).sorted();
|
||||
}
|
||||
}
|
||||
|
||||
/** In order to test whether a stream has any element, simply try to find one. */
|
||||
static final class IntStreamIsEmpty {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -1,521 +0,0 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.annotations.DoNotCall;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.function.Supplier;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import org.junit.jupiter.api.function.ThrowingSupplier;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
* Refaster rules to replace JUnit assertions with AssertJ equivalents.
|
||||
*
|
||||
* <p>Note that, while both libraries throw an {@link AssertionError} in case of an assertion
|
||||
* failure, the exact subtype used generally differs.
|
||||
*/
|
||||
// XXX: Not all `org.assertj.core.api.Assertions` methods have an associated Refaster rule yet;
|
||||
// expand this class.
|
||||
// XXX: Introduce a `@Matcher` on `Executable` and `ThrowingSupplier` expressions, such that they
|
||||
// are only matched if they are also compatible with the `ThrowingCallable` functional interface.
|
||||
// When implementing such a matcher, note that expressions with a non-void return type such as
|
||||
// `() -> toString()` match both `ThrowingSupplier` and `ThrowingCallable`, but `() -> "constant"`
|
||||
// is only compatible with the former.
|
||||
@OnlineDocumentation
|
||||
final class JUnitToAssertJRules {
|
||||
private JUnitToAssertJRules() {}
|
||||
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
Assertions.class,
|
||||
assertDoesNotThrow(() -> null),
|
||||
assertInstanceOf(null, null),
|
||||
assertThrows(null, null),
|
||||
assertThrowsExactly(null, null),
|
||||
(Runnable) () -> assertFalse(true),
|
||||
(Runnable) () -> assertNotNull(null),
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
(Runnable) () -> assertNull(null),
|
||||
(Runnable) () -> assertSame(null, null),
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
static final class ThrowNewAssertionError {
|
||||
@BeforeTemplate
|
||||
void before() {
|
||||
Assertions.fail();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
void after() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
static final class FailWithMessage<T> {
|
||||
@BeforeTemplate
|
||||
T before(String message) {
|
||||
return Assertions.fail(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
T after(String message) {
|
||||
return fail(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class FailWithMessageAndThrowable<T> {
|
||||
@BeforeTemplate
|
||||
T before(String message, Throwable throwable) {
|
||||
return Assertions.fail(message, throwable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
T after(String message, Throwable throwable) {
|
||||
return fail(message, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class FailWithThrowable {
|
||||
@BeforeTemplate
|
||||
void before(Throwable throwable) {
|
||||
Assertions.fail(throwable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
void after(Throwable throwable) {
|
||||
throw new AssertionError(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsTrue {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual) {
|
||||
assertTrue(actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean actual) {
|
||||
assertThat(actual).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsTrue {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, String message) {
|
||||
assertTrue(actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean actual, String message) {
|
||||
assertThat(actual).withFailMessage(message).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsTrue {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, Supplier<String> supplier) {
|
||||
assertTrue(actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean actual, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsFalse {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual) {
|
||||
assertFalse(actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean actual) {
|
||||
assertThat(actual).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsFalse {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, String message) {
|
||||
assertFalse(actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean actual, String message) {
|
||||
assertThat(actual).withFailMessage(message).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsFalse {
|
||||
@BeforeTemplate
|
||||
void before(boolean actual, Supplier<String> supplier) {
|
||||
assertFalse(actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(boolean actual, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsNull {
|
||||
@BeforeTemplate
|
||||
void before(Object actual) {
|
||||
assertNull(actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual) {
|
||||
assertThat(actual).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsNull {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, String message) {
|
||||
assertNull(actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, String message) {
|
||||
assertThat(actual).withFailMessage(message).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsNull {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Supplier<String> supplier) {
|
||||
assertNull(actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsNotNull {
|
||||
@BeforeTemplate
|
||||
void before(Object actual) {
|
||||
assertNotNull(actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual) {
|
||||
assertThat(actual).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsNotNull {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, String message) {
|
||||
assertNotNull(actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, String message) {
|
||||
assertThat(actual).withFailMessage(message).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsNotNull {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Supplier<String> supplier) {
|
||||
assertNotNull(actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsSameAs {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected) {
|
||||
assertSame(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Object expected) {
|
||||
assertThat(actual).isSameAs(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsSameAs {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected, String message) {
|
||||
assertSame(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Object expected, String message) {
|
||||
assertThat(actual).withFailMessage(message).isSameAs(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsSameAs {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected, Supplier<String> supplier) {
|
||||
assertSame(expected, actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Object expected, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isSameAs(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsNotSameAs {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected) {
|
||||
assertNotSame(expected, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Object expected) {
|
||||
assertThat(actual).isNotSameAs(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsNotSameAs {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected, String message) {
|
||||
assertNotSame(expected, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Object expected, String message) {
|
||||
assertThat(actual).withFailMessage(message).isNotSameAs(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsNotSameAs {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Object expected, Supplier<String> supplier) {
|
||||
assertNotSame(expected, actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Object expected, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isNotSameAs(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIsExactlyInstanceOf<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Class<T> clazz) {
|
||||
assertThrowsExactly(clazz, throwingCallable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> clazz) {
|
||||
assertThatThrownBy(throwingCallable).isExactlyInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByWithFailMessageStringIsExactlyInstanceOf<
|
||||
T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Class<T> clazz, String message) {
|
||||
assertThrowsExactly(clazz, throwingCallable, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> clazz, String message) {
|
||||
assertThatThrownBy(throwingCallable).withFailMessage(message).isExactlyInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByWithFailMessageSupplierIsExactlyInstanceOf<
|
||||
T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
|
||||
assertThrowsExactly(clazz, throwingCallable, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
|
||||
assertThatThrownBy(throwingCallable).withFailMessage(supplier).isExactlyInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIsInstanceOf<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Class<T> clazz) {
|
||||
assertThrows(clazz, throwingCallable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> clazz) {
|
||||
assertThatThrownBy(throwingCallable).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByWithFailMessageStringIsInstanceOf<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Class<T> clazz, String message) {
|
||||
assertThrows(clazz, throwingCallable, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> clazz, String message) {
|
||||
assertThatThrownBy(throwingCallable).withFailMessage(message).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByWithFailMessageSupplierIsInstanceOf<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
|
||||
assertThrows(clazz, throwingCallable, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
|
||||
assertThatThrownBy(throwingCallable).withFailMessage(supplier).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCodeDoesNotThrowAnyException {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable) {
|
||||
assertDoesNotThrow(throwingCallable);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(ThrowingSupplier<?> throwingCallable) {
|
||||
assertDoesNotThrow(throwingCallable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable) {
|
||||
assertThatCode(throwingCallable).doesNotThrowAnyException();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCodeWithFailMessageStringDoesNotThrowAnyException {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, String message) {
|
||||
assertDoesNotThrow(throwingCallable, message);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(ThrowingSupplier<?> throwingCallable, String message) {
|
||||
assertDoesNotThrow(throwingCallable, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, String message) {
|
||||
assertThatCode(throwingCallable).withFailMessage(message).doesNotThrowAnyException();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCodeWithFailMessageSupplierDoesNotThrowAnyException {
|
||||
@BeforeTemplate
|
||||
void before(Executable throwingCallable, Supplier<String> supplier) {
|
||||
assertDoesNotThrow(throwingCallable, supplier);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before(ThrowingSupplier<?> throwingCallable, Supplier<String> supplier) {
|
||||
assertDoesNotThrow(throwingCallable, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Supplier<String> supplier) {
|
||||
assertThatCode(throwingCallable).withFailMessage(supplier).doesNotThrowAnyException();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatIsInstanceOf<T> {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Class<T> clazz) {
|
||||
assertInstanceOf(clazz, actual);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Class<T> clazz) {
|
||||
assertThat(actual).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageStringIsInstanceOf<T> {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Class<T> clazz, String message) {
|
||||
assertInstanceOf(clazz, actual, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Class<T> clazz, String message) {
|
||||
assertThat(actual).withFailMessage(message).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatWithFailMessageSupplierIsInstanceOf<T> {
|
||||
@BeforeTemplate
|
||||
void before(Object actual, Class<T> clazz, Supplier<String> supplier) {
|
||||
assertInstanceOf(clazz, actual, supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(Object actual, Class<T> clazz, Supplier<String> supplier) {
|
||||
assertThat(actual).withFailMessage(supplier).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,22 +154,6 @@ final class LongStreamRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link LongStream#filter(LongPredicate)} before {@link LongStream#sorted()} to reduce the
|
||||
* number of elements to sort.
|
||||
*/
|
||||
static final class LongStreamFilterSorted {
|
||||
@BeforeTemplate
|
||||
LongStream before(LongStream stream, LongPredicate predicate) {
|
||||
return stream.sorted().filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
LongStream after(LongStream stream, LongPredicate predicate) {
|
||||
return stream.filter(predicate).sorted();
|
||||
}
|
||||
}
|
||||
|
||||
/** In order to test whether a stream has any element, simply try to find one. */
|
||||
static final class LongStreamIsEmpty {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Map} instances. */
|
||||
@OnlineDocumentation
|
||||
final class MapRules {
|
||||
private MapRules() {}
|
||||
|
||||
// XXX: We could add a rule for `new EnumMap(Map<K, ? extends V> m)`, but that constructor does
|
||||
// not allow an empty non-EnumMap to be provided.
|
||||
static final class CreateEnumMap<K extends Enum<K>, V> {
|
||||
@BeforeTemplate
|
||||
Map<K, V> before() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Map<K, V> after() {
|
||||
return new EnumMap<>(Refaster.<K>clazz());
|
||||
}
|
||||
}
|
||||
|
||||
static final class MapGetOrNull<K, V, T> {
|
||||
@BeforeTemplate
|
||||
@Nullable
|
||||
V before(Map<K, V> map, T key) {
|
||||
return map.getOrDefault(key, null);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@Nullable
|
||||
V after(Map<K, V> map, T key) {
|
||||
return map.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Map#isEmpty()} over more contrived alternatives. */
|
||||
static final class MapIsEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
boolean before(Map<K, V> map) {
|
||||
return Refaster.anyOf(map.keySet(), map.values(), map.entrySet()).isEmpty();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Map<K, V> map) {
|
||||
return map.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Map#size()} over more contrived alternatives. */
|
||||
static final class MapSize<K, V> {
|
||||
@BeforeTemplate
|
||||
int before(Map<K, V> map) {
|
||||
return Refaster.anyOf(map.keySet(), map.values(), map.entrySet()).size();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(Map<K, V> map) {
|
||||
return map.size();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Map#containsKey(Object)} over more contrived alternatives. */
|
||||
static final class MapContainsKey<K, V, T> {
|
||||
@BeforeTemplate
|
||||
boolean before(Map<K, V> map, T key) {
|
||||
return map.keySet().contains(key);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Map<K, V> map, T key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Map#containsValue(Object)} over more contrived alternatives. */
|
||||
static final class MapContainsValue<K, V, T> {
|
||||
@BeforeTemplate
|
||||
boolean before(Map<K, V> map, T value) {
|
||||
return map.values().contains(value);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Map<K, V> map, T value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily use {@link Map#entrySet()}. */
|
||||
static final class MapKeyStream<K, V> {
|
||||
@BeforeTemplate
|
||||
Stream<K> before(Map<K, V> map) {
|
||||
return map.entrySet().stream().map(Map.Entry::getKey);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<K> after(Map<K, V> map) {
|
||||
return map.keySet().stream();
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily use {@link Map#entrySet()}. */
|
||||
static final class MapValueStream<K, V> {
|
||||
@BeforeTemplate
|
||||
Stream<V> before(Map<K, V> map) {
|
||||
return map.entrySet().stream().map(Map.Entry::getValue);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<V> after(Map<K, V> map) {
|
||||
return map.values().stream();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Multimap}s. */
|
||||
@@ -50,8 +50,7 @@ final class MultimapRules {
|
||||
*/
|
||||
static final class MultimapGet<K, V> {
|
||||
@BeforeTemplate
|
||||
@Nullable
|
||||
Collection<V> before(Multimap<K, V> multimap, K key) {
|
||||
@Nullable Collection<V> before(Multimap<K, V> multimap, K key) {
|
||||
return Refaster.anyOf(multimap.asMap(), Multimaps.asMap(multimap)).get(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,14 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
import static java.util.Objects.requireNonNullElseGet;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with (possibly) null values. */
|
||||
@@ -47,18 +43,13 @@ final class NullRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Objects#requireNonNullElse(Object, Object)} over non-JDK or more contrived
|
||||
* alternatives.
|
||||
*/
|
||||
// XXX: This rule is not valid in case `second` is `@Nullable`: in that case the Guava and
|
||||
// `Optional` variants will return `null`, where the `requireNonNullElse` alternative will throw
|
||||
// an NPE.
|
||||
/** Prefer {@link Objects#requireNonNullElse(Object, Object)} over the Guava alternative. */
|
||||
// XXX: This rule is not valid in case `second` is `@Nullable`: in that case the Guava variant
|
||||
// will return `null`, while the JDK variant will throw an NPE.
|
||||
static final class RequireNonNullElse<T> {
|
||||
@BeforeTemplate
|
||||
T before(T first, T second) {
|
||||
return Refaster.anyOf(
|
||||
MoreObjects.firstNonNull(first, second), Optional.ofNullable(first).orElse(second));
|
||||
return MoreObjects.firstNonNull(first, second);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -68,26 +59,6 @@ final class NullRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Objects#requireNonNullElseGet(Object, Supplier)} over more contrived
|
||||
* alternatives.
|
||||
*/
|
||||
// XXX: This rule is not valid in case `supplier` yields `@Nullable` values: in that case the
|
||||
// `Optional` variant will return `null`, where the `requireNonNullElseGet` alternative will throw
|
||||
// an NPE.
|
||||
static final class RequireNonNullElseGet<T, S extends T> {
|
||||
@BeforeTemplate
|
||||
T before(T object, Supplier<S> supplier) {
|
||||
return Optional.ofNullable(object).orElseGet(supplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
T after(T object, Supplier<S> supplier) {
|
||||
return requireNonNullElseGet(object, supplier);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Objects#isNull(Object)} over the equivalent lambda function. */
|
||||
static final class IsNullFunction<T> {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Optional}s. */
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.time.Duration;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -27,7 +26,6 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -61,45 +59,6 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#empty()} over more contrived alternatives. */
|
||||
static final class MonoEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before() {
|
||||
return Refaster.anyOf(Mono.justOrEmpty(null), Mono.justOrEmpty(Optional.empty()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after() {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#just(Object)} over more contrived alternatives. */
|
||||
static final class MonoJust<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(T value) {
|
||||
return Mono.justOrEmpty(Optional.of(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(T value) {
|
||||
return Mono.just(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#justOrEmpty(Object)} over more contrived alternatives. */
|
||||
static final class MonoJustOrEmpty<@Nullable T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(T value) {
|
||||
return Mono.justOrEmpty(Optional.ofNullable(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(T value) {
|
||||
return Mono.justOrEmpty(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#justOrEmpty(Optional)} over more verbose alternatives. */
|
||||
// XXX: If `optional` is a constant and effectively-final expression then the `Mono.defer` can be
|
||||
// dropped. Should look into Refaster support for identifying this.
|
||||
@@ -119,40 +78,6 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to avoid expressions of type {@code Optional<Mono<T>>}, but if you must map an {@link
|
||||
* Optional} to this type, prefer using {@link Mono#just(Object)}.
|
||||
*/
|
||||
static final class OptionalMapMonoJust<T> {
|
||||
@BeforeTemplate
|
||||
Optional<Mono<T>> before(Optional<T> optional) {
|
||||
return optional.map(Mono::justOrEmpty);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Optional<Mono<T>> after(Optional<T> optional) {
|
||||
return optional.map(Mono::just);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer a {@link Mono#justOrEmpty(Optional)} and {@link Mono#switchIfEmpty(Mono)} chain over
|
||||
* more contrived alternatives.
|
||||
*
|
||||
* <p>In particular, avoid mixing of the {@link Optional} and {@link Mono} APIs.
|
||||
*/
|
||||
static final class MonoFromOptionalSwitchIfEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Optional<T> optional, Mono<T> mono) {
|
||||
return optional.map(Mono::just).orElse(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Optional<T> optional, Mono<T> mono) {
|
||||
return Mono.justOrEmpty(optional).switchIfEmpty(mono);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Mono#zip(Mono, Mono)} over a chained {@link Mono#zipWith(Mono)}, as the former
|
||||
* better conveys that the {@link Mono}s may be subscribed to concurrently, and generalizes to
|
||||
@@ -339,44 +264,13 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#defaultIfEmpty(Object)} over more contrived alternatives. */
|
||||
static final class MonoDefaultIfEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Mono<T> mono, T object) {
|
||||
return mono.switchIfEmpty(Mono.just(object));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Mono<T> mono, T object) {
|
||||
return mono.defaultIfEmpty(object);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#defaultIfEmpty(Object)} over more contrived alternatives. */
|
||||
static final class FluxDefaultIfEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux, T object) {
|
||||
return flux.switchIfEmpty(Refaster.anyOf(Mono.just(object), Flux.just(object)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux, T object) {
|
||||
return flux.defaultIfEmpty(object);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily transform a {@link Mono} to an equivalent instance. */
|
||||
static final class MonoIdentity<T> {
|
||||
/** Don't unnecessarily pass an empty publisher to {@link Mono#switchIfEmpty(Mono)}. */
|
||||
static final class MonoSwitchIfEmptyOfEmptyPublisher<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Mono<T> mono) {
|
||||
return mono.switchIfEmpty(Mono.empty());
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
Mono<@Nullable Void> before2(Mono<@Nullable Void> mono) {
|
||||
return mono.then();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Mono<T> mono) {
|
||||
return mono;
|
||||
@@ -400,10 +294,7 @@ final class ReactorRules {
|
||||
static final class FluxConcatMap<T, S> {
|
||||
@BeforeTemplate
|
||||
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMap(function, 1),
|
||||
flux.flatMapSequential(function, 1),
|
||||
flux.map(function).concatMap(identity()));
|
||||
return Refaster.anyOf(flux.flatMap(function, 1), flux.flatMapSequential(function, 1));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -420,9 +311,7 @@ final class ReactorRules {
|
||||
Function<? super T, ? extends Publisher<? extends S>> function,
|
||||
int prefetch) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMap(function, 1, prefetch),
|
||||
flux.flatMapSequential(function, 1, prefetch),
|
||||
flux.map(function).concatMap(identity(), prefetch));
|
||||
flux.flatMap(function, 1, prefetch), flux.flatMapSequential(function, 1, prefetch));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -670,8 +559,7 @@ final class ReactorRules {
|
||||
static final class MonoFlux<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Mono<T> mono) {
|
||||
return Refaster.anyOf(
|
||||
mono.flatMapMany(Mono::just), mono.flatMapMany(Flux::just), Flux.concat(mono));
|
||||
return Flux.concat(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -680,19 +568,6 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer direct invocation of {@link Mono#then()}} over more contrived alternatives. */
|
||||
static final class MonoThen<T> {
|
||||
@BeforeTemplate
|
||||
Mono<@Nullable Void> before(Mono<T> mono) {
|
||||
return mono.flux().then();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<@Nullable Void> after(Mono<T> mono) {
|
||||
return mono.then();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer a collection using {@link MoreCollectors#toOptional()} over more contrived alternatives.
|
||||
*/
|
||||
@@ -701,7 +576,9 @@ final class ReactorRules {
|
||||
static final class MonoCollectToOptional<T> {
|
||||
@BeforeTemplate
|
||||
Mono<Optional<T>> before(Mono<T> mono) {
|
||||
return mono.map(Optional::of).defaultIfEmpty(Optional.empty());
|
||||
return Refaster.anyOf(
|
||||
mono.map(Optional::of).defaultIfEmpty(Optional.empty()),
|
||||
mono.map(Optional::of).switchIfEmpty(Mono.just(Optional.empty())));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -737,32 +614,6 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#flatMap(Function)} over more contrived alternatives. */
|
||||
static final class MonoFlatMap<S, T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
|
||||
return mono.map(function).flatMap(identity());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
|
||||
return mono.flatMap(function);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#flatMapMany(Function)} over more contrived alternatives. */
|
||||
static final class MonoFlatMapMany<S, T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
|
||||
return mono.map(function).flatMapMany(identity());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
|
||||
return mono.flatMapMany(function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#concatMapIterable(Function)} over alternatives that require an additional
|
||||
* subscription.
|
||||
@@ -1081,38 +932,6 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link Flux#filter(Predicate)} before {@link Flux#sort()} to reduce the number of
|
||||
* elements to sort.
|
||||
*/
|
||||
static final class FluxFilterSort<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux, Predicate<? super T> predicate) {
|
||||
return flux.sort().filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux, Predicate<? super T> predicate) {
|
||||
return flux.filter(predicate).sort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link Flux#filter(Predicate)} before {@link Flux#sort(Comparator)} to reduce the number
|
||||
* of elements to sort.
|
||||
*/
|
||||
static final class FluxFilterSortWithComparator<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux, Predicate<? super T> predicate, Comparator<? super T> comparator) {
|
||||
return flux.sort(comparator).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux, Predicate<? super T> predicate, Comparator<? super T> comparator) {
|
||||
return flux.filter(predicate).sort(comparator);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
|
||||
// XXX: Consider introducing an `IsEmpty` matcher that identifies a wide range of guaranteed-empty
|
||||
// `Collection` and `Map` expressions.
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.reactivex.Flowable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import reactor.adapter.rxjava.RxJava2Adapter;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -77,9 +77,6 @@ final class StreamRules {
|
||||
* Prefer {@link Arrays#stream(Object[])} over {@link Stream#of(Object[])}, as the former is
|
||||
* clearer.
|
||||
*/
|
||||
// XXX: Introduce a `Matcher` that identifies `Refaster.asVarargs(...)` invocations and annotate
|
||||
// the `array` parameter as `@NotMatches(IsRefasterAsVarargs.class)`. Then elsewhere
|
||||
// `@SuppressWarnings("StreamOfArray")` annotations can be dropped.
|
||||
static final class StreamOfArray<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(T[] array) {
|
||||
@@ -167,40 +164,6 @@ final class StreamRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link Stream#filter(Predicate)} before {@link Stream#sorted()} to reduce the number of
|
||||
* elements to sort.
|
||||
*/
|
||||
static final class StreamFilterSorted<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Stream<T> stream, Predicate<? super T> predicate) {
|
||||
return stream.sorted().filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<T> after(Stream<T> stream, Predicate<? super T> predicate) {
|
||||
return stream.filter(predicate).sorted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply {@link Stream#filter(Predicate)} before {@link Stream#sorted(Comparator)} to reduce the
|
||||
* number of elements to sort.
|
||||
*/
|
||||
static final class StreamFilterSortedWithComparator<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(
|
||||
Stream<T> stream, Predicate<? super T> predicate, Comparator<? super T> comparator) {
|
||||
return stream.sorted(comparator).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<T> after(
|
||||
Stream<T> stream, Predicate<? super T> predicate, Comparator<? super T> comparator) {
|
||||
return stream.filter(predicate).sorted(comparator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Where possible, clarify that a mapping operation will be applied only to a single stream
|
||||
* element.
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.nullness.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link String}s. */
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.Set;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.testng.Assert;
|
||||
import org.testng.Assert.ThrowingRunnable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
* Refaster rules that replace TestNG assertions with equivalent AssertJ assertions.
|
||||
@@ -73,7 +72,6 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
// XXX: As-is these rules do not result in a complete migration:
|
||||
// - Expressions containing comments are skipped due to a limitation of Refaster.
|
||||
// - Assertions inside lambda expressions are also skipped. Unclear why.
|
||||
@OnlineDocumentation
|
||||
final class TestNGToAssertJRules {
|
||||
private TestNGToAssertJRules() {}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Picnic Refaster rules. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@org.jspecify.annotations.NullMarked
|
||||
@org.jspecify.nullness.NullMarked
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
@@ -94,11 +94,13 @@ final class AutowiredConstructorTest {
|
||||
"",
|
||||
"interface Container {",
|
||||
" class A {",
|
||||
"",
|
||||
" @Deprecated",
|
||||
" A() {}",
|
||||
" }",
|
||||
"",
|
||||
" class B {",
|
||||
"",
|
||||
" B(String x) {}",
|
||||
" }",
|
||||
"}")
|
||||
|
||||
@@ -76,18 +76,8 @@ final class EmptyMethodTest {
|
||||
" void instanceMethod() {}",
|
||||
"",
|
||||
" static void staticMethod() {}",
|
||||
"",
|
||||
" static void staticMethodWithComment() {",
|
||||
" /* Foo. */",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"final class A {",
|
||||
" static void staticMethodWithComment() {",
|
||||
" /* Foo. */",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines("A.java", "final class A {}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,7 @@ final class IdentityConversionTest {
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
|
||||
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
|
||||
"",
|
||||
"Foo.java",
|
||||
"import com.google.common.collect.ImmutableBiMap;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableListMultimap;",
|
||||
@@ -31,14 +28,12 @@ final class IdentityConversionTest {
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSetMultimap;",
|
||||
"import com.google.common.collect.ImmutableTable;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import reactor.adapter.rxjava.RxJava2Adapter;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
"public final class Foo {",
|
||||
" public void foo() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Boolean b1 = Boolean.valueOf(Boolean.FALSE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
@@ -118,13 +113,6 @@ final class IdentityConversionTest {
|
||||
" // BUG: Diagnostic contains:",
|
||||
" short s4 = Short.valueOf(Short.MIN_VALUE);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String boolStr = Boolean.valueOf(Boolean.FALSE).toString();",
|
||||
" int boolHash = Boolean.valueOf(false).hashCode();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" int byteHash = Byte.valueOf((Byte) Byte.MIN_VALUE).hashCode();",
|
||||
" String byteStr = Byte.valueOf(Byte.MIN_VALUE).toString();",
|
||||
"",
|
||||
" String str1 = String.valueOf(0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String str2 = String.valueOf(\"1\");",
|
||||
@@ -155,15 +143,7 @@ final class IdentityConversionTest {
|
||||
" ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Matcher allOf1 = Matchers.allOf(instanceMethod());",
|
||||
" Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Matcher anyOf1 = Matchers.anyOf(staticMethod());",
|
||||
" Matcher anyOf2 = Matchers.anyOf(instanceMethod(), staticMethod());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux2 = Flux.concat(Flux.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
@@ -174,9 +154,9 @@ final class IdentityConversionTest {
|
||||
" Flux<Integer> flux5 = Flux.merge(Flux.just(1));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono<Integer> mono1 = Mono.from(Mono.just(1));",
|
||||
" Mono<Integer> m1 = Mono.from(Mono.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono<Integer> mono2 = Mono.fromDirect(Mono.just(1));",
|
||||
" Mono<Integer> m2 = Mono.fromDirect(Mono.just(1));",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
@@ -187,15 +167,12 @@ final class IdentityConversionTest {
|
||||
refactoringTestHelper
|
||||
.setFixChooser(FixChoosers.FIRST)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
|
||||
"Foo.java",
|
||||
"import static org.mockito.Mockito.when;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.Collection;",
|
||||
"import org.reactivestreams.Publisher;",
|
||||
@@ -203,8 +180,8 @@ final class IdentityConversionTest {
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
"public final class Foo {",
|
||||
" public void foo() {",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
@@ -229,23 +206,18 @@ final class IdentityConversionTest {
|
||||
" Object o1 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
" Object o2 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
"",
|
||||
" Matcher matcher = Matchers.allOf(staticMethod());",
|
||||
"",
|
||||
" when(\"foo\".contains(\"f\")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));",
|
||||
" }",
|
||||
"",
|
||||
" void bar(Publisher<Integer> publisher) {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
|
||||
"Foo.java",
|
||||
"import static org.mockito.Mockito.when;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.Collection;",
|
||||
"import org.reactivestreams.Publisher;",
|
||||
@@ -253,8 +225,8 @@ final class IdentityConversionTest {
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
"public final class Foo {",
|
||||
" public void foo() {",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.of();",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
@@ -279,8 +251,6 @@ final class IdentityConversionTest {
|
||||
" Object o1 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
" Object o2 = ImmutableSet.of();",
|
||||
"",
|
||||
" Matcher matcher = staticMethod();",
|
||||
"",
|
||||
" when(\"foo\".contains(\"f\")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));",
|
||||
" }",
|
||||
"",
|
||||
@@ -294,14 +264,14 @@ final class IdentityConversionTest {
|
||||
refactoringTestHelper
|
||||
.setFixChooser(FixChoosers.SECOND)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"Foo.java",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.util.ArrayList;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
"public final class Foo {",
|
||||
" public void foo() {",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
@@ -310,14 +280,14 @@ final class IdentityConversionTest {
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"Foo.java",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.util.ArrayList;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
"public final class Foo {",
|
||||
" public void foo() {",
|
||||
" @SuppressWarnings(\"IdentityConversion\")",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
|
||||
@@ -17,28 +17,12 @@ final class IsInstanceLambdaUsageTest {
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Integer localVariable = 0;",
|
||||
"",
|
||||
" Stream.of(0).map(i -> i + 1);",
|
||||
" Stream.of(1).filter(Integer.class::isInstance);",
|
||||
" Stream.of(2).filter(i -> i.getClass() instanceof Class);",
|
||||
" Stream.of(3).filter(i -> localVariable instanceof Integer);",
|
||||
" // XXX: Ideally this case is also flagged. Pick this up in the context of merging the",
|
||||
" // `IsInstanceLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that",
|
||||
" // simplifies unnecessary block lambda expressions.",
|
||||
" Stream.of(4)",
|
||||
" .filter(",
|
||||
" i -> {",
|
||||
" return localVariable instanceof Integer;",
|
||||
" });",
|
||||
" Flux.just(5, \"foo\").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(6).filter(i -> i instanceof Integer);",
|
||||
" Stream.of(1).filter(i -> i instanceof Integer);",
|
||||
" Stream.of(2).filter(Integer.class::isInstance);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class JUnitClassModifiersTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(JUnitClassModifiers.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(JUnitClassModifiers.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"Container.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.springframework.boot.test.context.TestConfiguration;",
|
||||
"import org.springframework.context.annotation.Configuration;",
|
||||
"",
|
||||
"class Container {",
|
||||
" final class FinalAndPackagePrivate {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" final class FinalAndPackagePrivateWithCustomTestMethod {",
|
||||
" @ParameterizedTest",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" public abstract class Abstract {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @Configuration",
|
||||
" class WithConfigurationAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @TestConfiguration",
|
||||
" class WithConfigurationMetaAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private final class Private {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected final class Protected {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public final class Public {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" class NonFinal {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" class NonFinalWithCustomTestMethod {",
|
||||
" @ParameterizedTest",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @Configuration",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public class PublicWithConfigurationAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @TestConfiguration",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected class ProtectedWithConfigurationMetaAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.springframework.context.annotation.Configuration;",
|
||||
"",
|
||||
"public class A {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" @Configuration",
|
||||
" private static class B {",
|
||||
" @Test",
|
||||
" void bar() {}",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.springframework.context.annotation.Configuration;",
|
||||
"",
|
||||
"final class A {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" @Configuration",
|
||||
" static class B {",
|
||||
" @Test",
|
||||
" void bar() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -91,9 +91,6 @@ final class JUnitMethodDeclarationTest {
|
||||
" private void tearDown8() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void test() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void method1() {}",
|
||||
"",
|
||||
" @Test",
|
||||
@@ -147,13 +144,8 @@ final class JUnitMethodDeclarationTest {
|
||||
" void test5() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that a method named `toString` is already defined in this",
|
||||
" // class or a supertype)",
|
||||
" void testToString() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that a method named `overload` is already defined in this",
|
||||
" // class or a supertype)",
|
||||
" // BUG: Diagnostic contains: (but note that a method named `overload` already exists in this",
|
||||
" // class)",
|
||||
" void testOverload() {}",
|
||||
"",
|
||||
" void overload() {}",
|
||||
@@ -163,20 +155,8 @@ final class JUnitMethodDeclarationTest {
|
||||
" void testArguments() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)",
|
||||
" // BUG: Diagnostic contains: (but note that `public` is a reserved keyword)",
|
||||
" void testPublic() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `null` is not a valid identifier)",
|
||||
" void testNull() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void testRecord() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
@@ -238,10 +218,6 @@ final class JUnitMethodDeclarationTest {
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void test() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void method1() {}",
|
||||
"",
|
||||
" @Override",
|
||||
@@ -291,10 +267,6 @@ final class JUnitMethodDeclarationTest {
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testToString() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testOverload() {}",
|
||||
"",
|
||||
" @Override",
|
||||
@@ -307,17 +279,6 @@ final class JUnitMethodDeclarationTest {
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testPublic() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testNull() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testRecord() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"C.java",
|
||||
@@ -391,9 +352,6 @@ final class JUnitMethodDeclarationTest {
|
||||
" protected void quux() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public void testToString() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public void testOverload() {}",
|
||||
"",
|
||||
" void overload() {}",
|
||||
@@ -403,9 +361,6 @@ final class JUnitMethodDeclarationTest {
|
||||
"",
|
||||
" @Test",
|
||||
" private void testClass() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" private void testTrue() {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
@@ -452,9 +407,6 @@ final class JUnitMethodDeclarationTest {
|
||||
" void quux() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testToString() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testOverload() {}",
|
||||
"",
|
||||
" void overload() {}",
|
||||
@@ -464,9 +416,6 @@ final class JUnitMethodDeclarationTest {
|
||||
"",
|
||||
" @Test",
|
||||
" void testClass() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testTrue() {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -39,19 +39,4 @@ final class NestedOptionalsTest {
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationOptionalTypeNotLoaded() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.time.Duration;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Duration.ofSeconds(1);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,6 @@ import org.junit.jupiter.api.Test;
|
||||
final class RequestParamTypeTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RequestParamType.class, getClass());
|
||||
private final CompilationTestHelper restrictedCompilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RequestParamType.class, getClass())
|
||||
.setArgs(
|
||||
"-XepOpt:RequestParamType:SupportedCustomTypes=com.google.common.collect.ImmutableSet,com.google.common.collect.ImmutableSortedMultiset");
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -23,7 +19,7 @@ final class RequestParamTypeTest {
|
||||
"import java.util.List;",
|
||||
"import java.util.Map;",
|
||||
"import java.util.Set;",
|
||||
"import org.jspecify.annotations.Nullable;",
|
||||
"import org.jspecify.nullness.Nullable;",
|
||||
"import org.springframework.web.bind.annotation.DeleteMapping;",
|
||||
"import org.springframework.web.bind.annotation.GetMapping;",
|
||||
"import org.springframework.web.bind.annotation.PostMapping;",
|
||||
@@ -67,53 +63,4 @@ final class RequestParamTypeTest {
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationRestricted() {
|
||||
restrictedCompilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableBiMap;",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import com.google.common.collect.ImmutableMultiset;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSortedMultiset;",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import org.springframework.web.bind.annotation.GetMapping;",
|
||||
"import org.springframework.web.bind.annotation.RequestParam;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @GetMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A immutableCollection(@RequestParam ImmutableCollection<String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A immutableList(@RequestParam ImmutableList<String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" A immutableSet(@RequestParam ImmutableSet<String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" A immutableSortedSet(@RequestParam ImmutableSortedSet<String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A immutableMultiset(@RequestParam ImmutableMultiset<String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" A immutableSortedMultiset(@RequestParam ImmutableSortedMultiset<String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A immutableMap(@RequestParam ImmutableMap<String, String> param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A immutableBiMap(@RequestParam ImmutableBiMap<String, String> param);",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public final class SimplifyTimeAnnotationCheckTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(SimplifyTimeAnnotationCheck.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(SimplifyTimeAnnotationCheck.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.concurrent.TimeUnit;",
|
||||
"import org.junit.jupiter.api.Timeout;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Timeout(6)",
|
||||
" A noSimplification();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Timeout(60)",
|
||||
" A simple();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Timeout(value = 60 * 1000, unit = TimeUnit.MILLISECONDS)",
|
||||
" A explicitUnit();",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationBannedField() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"interface A {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Scheduled(fixedDelay = 6_000)",
|
||||
" A scheduledFixedDelay();",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 6_000, fixedRateString = \"\")",
|
||||
" A bannedAttribute();",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"in/A.java",
|
||||
"import org.junit.jupiter.api.Timeout;",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Timeout(value = 60)",
|
||||
" A simple();",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 6_000)",
|
||||
" A scheduledFixedDelay();",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 5_000, initialDelay = 6_000, fixedRate = 7_000)",
|
||||
" A scheduledMultiple();",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 60_000, initialDelay = 6_000, fixedRate = 7_000)",
|
||||
" A scheduledCommonUnit();",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 5, initialDelay = 6_000, fixedRate = 7_000)",
|
||||
" A scheduledNoSimplification();",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import static java.util.concurrent.TimeUnit.MINUTES;",
|
||||
"import static java.util.concurrent.TimeUnit.SECONDS;",
|
||||
"",
|
||||
"import org.junit.jupiter.api.Timeout;",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Timeout(value = 1, unit = MINUTES)",
|
||||
" A simple();",
|
||||
"",
|
||||
" @Scheduled(timeUnit = SECONDS, fixedDelay = 6)",
|
||||
" A scheduledFixedDelay();",
|
||||
"",
|
||||
" @Scheduled(timeUnit = SECONDS, fixedDelay = 5, initialDelay = 6, fixedRate = 7)",
|
||||
" A scheduledMultiple();",
|
||||
"",
|
||||
" @Scheduled(timeUnit = SECONDS, fixedDelay = 60, initialDelay = 6, fixedRate = 7)",
|
||||
" A scheduledCommonUnit();",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 5, initialDelay = 6_000, fixedRate = 7_000)",
|
||||
" A scheduledNoSimplification();",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementValueOnly() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"in/A.java",
|
||||
"import org.junit.jupiter.api.Timeout;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Timeout(60)",
|
||||
" A simple();",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import static java.util.concurrent.TimeUnit.MINUTES;",
|
||||
"",
|
||||
"import org.junit.jupiter.api.Timeout;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Timeout(value = 1, unit = MINUTES)",
|
||||
" A simple();",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementFqcn() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"in/A.java",
|
||||
"interface A {",
|
||||
" @org.junit.jupiter.api.Timeout(60)",
|
||||
" A simple();",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"out/A.java",
|
||||
"import static java.util.concurrent.TimeUnit.MINUTES;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @org.junit.jupiter.api.Timeout(value = 1, unit = MINUTES)",
|
||||
" A simple();",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ final class SpringMvcAnnotationTest {
|
||||
"import static org.springframework.web.bind.annotation.RequestMethod.DELETE;",
|
||||
"import static org.springframework.web.bind.annotation.RequestMethod.GET;",
|
||||
"import static org.springframework.web.bind.annotation.RequestMethod.HEAD;",
|
||||
"import static org.springframework.web.bind.annotation.RequestMethod.PATCH;",
|
||||
"import static org.springframework.web.bind.annotation.RequestMethod.POST;",
|
||||
"import static org.springframework.web.bind.annotation.RequestMethod.PUT;",
|
||||
"",
|
||||
@@ -50,7 +49,7 @@ final class SpringMvcAnnotationTest {
|
||||
" @RequestMapping(method = {DELETE})",
|
||||
" A delete();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @RequestMapping(method = {PATCH})",
|
||||
" @RequestMapping(method = {org.springframework.web.bind.annotation.RequestMethod.PATCH})",
|
||||
" A patch();",
|
||||
"",
|
||||
" @RequestMapping(method = HEAD)",
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugCheckerRefactoringTestHelper.newInstance;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class StringCaseLocaleUsageTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(StringCaseLocaleUsage.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
newInstance(StringCaseLocaleUsage.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static java.util.Locale.ROOT;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" \"a\".toLowerCase(Locale.ROOT);",
|
||||
" \"a\".toUpperCase(Locale.ROOT);",
|
||||
" \"b\".toLowerCase(ROOT);",
|
||||
" \"b\".toUpperCase(ROOT);",
|
||||
" \"c\".toLowerCase(Locale.getDefault());",
|
||||
" \"c\".toUpperCase(Locale.getDefault());",
|
||||
" \"d\".toLowerCase(Locale.ENGLISH);",
|
||||
" \"d\".toUpperCase(Locale.ENGLISH);",
|
||||
" \"e\".toLowerCase(new Locale(\"foo\"));",
|
||||
" \"e\".toUpperCase(new Locale(\"foo\"));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"f\".toLowerCase();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" \"g\".toUpperCase();",
|
||||
"",
|
||||
" String h = \"h\";",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" h.toLowerCase();",
|
||||
" String i = \"i\";",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" i.toUpperCase();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementFirstSuggestedFix() {
|
||||
refactoringTestHelper
|
||||
.setFixChooser(FixChoosers.FIRST)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" \"a\".toLowerCase(/* Comment with parens: (). */ );",
|
||||
" \"b\".toUpperCase();",
|
||||
" \"c\".toLowerCase().toString();",
|
||||
"",
|
||||
" toString().toLowerCase();",
|
||||
" toString().toUpperCase /* Comment with parens: (). */();",
|
||||
"",
|
||||
" this.toString().toLowerCase() /* Comment with parens: (). */;",
|
||||
" this.toString().toUpperCase();",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import java.util.Locale;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" \"a\".toLowerCase(/* Comment with parens: (). */ Locale.ROOT);",
|
||||
" \"b\".toUpperCase(Locale.ROOT);",
|
||||
" \"c\".toLowerCase(Locale.ROOT).toString();",
|
||||
"",
|
||||
" toString().toLowerCase(Locale.ROOT);",
|
||||
" toString().toUpperCase /* Comment with parens: (). */(Locale.ROOT);",
|
||||
"",
|
||||
" this.toString().toLowerCase(Locale.ROOT) /* Comment with parens: (). */;",
|
||||
" this.toString().toUpperCase(Locale.ROOT);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementSecondSuggestedFix() {
|
||||
refactoringTestHelper
|
||||
.setFixChooser(FixChoosers.SECOND)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" \"a\".toLowerCase();",
|
||||
" \"b\".toUpperCase(/* Comment with parens: (). */ );",
|
||||
" \"c\".toLowerCase().toString();",
|
||||
"",
|
||||
" toString().toLowerCase();",
|
||||
" toString().toUpperCase /* Comment with parens: (). */();",
|
||||
"",
|
||||
" this.toString().toLowerCase() /* Comment with parens: (). */;",
|
||||
" this.toString().toUpperCase();",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import java.util.Locale;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" \"a\".toLowerCase(Locale.getDefault());",
|
||||
" \"b\".toUpperCase(/* Comment with parens: (). */ Locale.getDefault());",
|
||||
" \"c\".toLowerCase(Locale.getDefault()).toString();",
|
||||
"",
|
||||
" toString().toLowerCase(Locale.getDefault());",
|
||||
" toString().toUpperCase /* Comment with parens: (). */(Locale.getDefault());",
|
||||
"",
|
||||
" this.toString().toLowerCase(Locale.getDefault()) /* Comment with parens: (). */;",
|
||||
" this.toString().toUpperCase(Locale.getDefault());",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.ErrorProneOptions;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
final class FlagsTest {
|
||||
private static Stream<Arguments> getListTestCases() {
|
||||
/* { args, flag, expected } */
|
||||
return Stream.of(
|
||||
arguments(ImmutableList.of(), "Foo", ImmutableList.of()),
|
||||
arguments(ImmutableList.of("-XepOpt:Foo=bar,baz"), "Qux", ImmutableList.of()),
|
||||
arguments(ImmutableList.of("-XepOpt:Foo="), "Foo", ImmutableList.of()),
|
||||
arguments(ImmutableList.of("-XepOpt:Foo=bar"), "Foo", ImmutableList.of("bar")),
|
||||
arguments(ImmutableList.of("-XepOpt:Foo=bar,baz"), "Foo", ImmutableList.of("bar", "baz")),
|
||||
arguments(ImmutableList.of("-XepOpt:Foo=,"), "Foo", ImmutableList.of("", "")));
|
||||
}
|
||||
|
||||
@MethodSource("getListTestCases")
|
||||
@ParameterizedTest
|
||||
void getList(ImmutableList<String> args, String flag, ImmutableList<String> expected) {
|
||||
assertThat(Flags.getList(ErrorProneOptions.processArgs(args).getFlags(), flag))
|
||||
.containsExactlyElementsOf(expected);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
final class JavaKeywordsTest {
|
||||
private static Stream<Arguments> isValidIdentifierTestCases() {
|
||||
/* { str, expected } */
|
||||
return Stream.of(
|
||||
arguments("", false),
|
||||
arguments("public", false),
|
||||
arguments("true", false),
|
||||
arguments("false", false),
|
||||
arguments("null", false),
|
||||
arguments("0", false),
|
||||
arguments("\0", false),
|
||||
arguments("a%\0", false),
|
||||
arguments("a", true),
|
||||
arguments("a0", true),
|
||||
arguments("_a0", true),
|
||||
arguments("test", true));
|
||||
}
|
||||
|
||||
@MethodSource("isValidIdentifierTestCases")
|
||||
@ParameterizedTest
|
||||
void isValidIdentifier(String str, boolean expected) {
|
||||
assertThat(JavaKeywords.isValidIdentifier(str)).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.function.BiFunction;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MoreASTHelpersTest {
|
||||
@Test
|
||||
void findMethods() {
|
||||
CompilationTestHelper.newInstance(FindMethodsTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" // BUG: Diagnostic contains: {foo=1, bar=2, baz=0}",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: {foo=1, bar=2, baz=0}",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: {foo=1, bar=2, baz=0}",
|
||||
" void bar(int i) {}",
|
||||
"",
|
||||
" static class B {",
|
||||
" // BUG: Diagnostic contains: {foo=0, bar=1, baz=1}",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: {foo=0, bar=1, baz=1}",
|
||||
" void baz() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodExistsInEnclosingClass() {
|
||||
CompilationTestHelper.newInstance(MethodExistsTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" // BUG: Diagnostic contains: {foo=true, bar=true, baz=false}",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: {foo=true, bar=true, baz=false}",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: {foo=true, bar=true, baz=false}",
|
||||
" void bar(int i) {}",
|
||||
"",
|
||||
" static class B {",
|
||||
" // BUG: Diagnostic contains: {foo=false, bar=true, baz=true}",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: {foo=false, bar=true, baz=true}",
|
||||
" void baz() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
private static String createDiagnosticsMessage(
|
||||
BiFunction<String, VisitorState, Object> valueFunction, VisitorState state) {
|
||||
return Maps.toMap(ImmutableSet.of("foo", "bar", "baz"), key -> valueFunction.apply(key, state))
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that delegates to {@link MoreASTHelpers#findMethods(CharSequence,
|
||||
* VisitorState)}.
|
||||
*/
|
||||
@BugPattern(summary = "Interacts with `MoreASTHelpers` for testing purposes", severity = ERROR)
|
||||
public static final class FindMethodsTestChecker extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
return buildDescription(tree)
|
||||
.setMessage(
|
||||
createDiagnosticsMessage(
|
||||
(methodName, s) -> MoreASTHelpers.findMethods(methodName, s).size(), state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that delegates to {@link
|
||||
* MoreASTHelpers#methodExistsInEnclosingClass(CharSequence, VisitorState)}.
|
||||
*/
|
||||
@BugPattern(summary = "Interacts with `MoreASTHelpers` for testing purposes", severity = ERROR)
|
||||
public static final class MethodExistsTestChecker extends BugChecker
|
||||
implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
return buildDescription(tree)
|
||||
.setMessage(createDiagnosticsMessage(MoreASTHelpers::methodExistsInEnclosingClass, state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.HAS_METHOD_SOURCE;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.SETUP_OR_TEARDOWN_METHOD;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.TEST_METHOD;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MoreJUnitMatchersTest {
|
||||
@Test
|
||||
void methodMatchers() {
|
||||
CompilationTestHelper.newInstance(MethodMatchersTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"import org.junit.jupiter.api.RepeatedTest;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" @BeforeAll",
|
||||
" // BUG: Diagnostic contains: SETUP_OR_TEARDOWN_METHOD",
|
||||
" public void beforeAll() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: TEST_METHOD, SETUP_OR_TEARDOWN_METHOD",
|
||||
" protected void beforeEachAndTest() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" // BUG: Diagnostic contains: SETUP_OR_TEARDOWN_METHOD",
|
||||
" private void afterEach() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" // BUG: Diagnostic contains: SETUP_OR_TEARDOWN_METHOD",
|
||||
" private void afterAll() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: TEST_METHOD",
|
||||
" void test() {}",
|
||||
"",
|
||||
" private static Stream<Arguments> booleanArgs() {",
|
||||
" return Stream.of(arguments(false), arguments(true));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"booleanArgs\")",
|
||||
" // BUG: Diagnostic contains: TEST_METHOD, HAS_METHOD_SOURCE",
|
||||
" void parameterizedTest(boolean b) {}",
|
||||
"",
|
||||
" @RepeatedTest(2)",
|
||||
" // BUG: Diagnostic contains: TEST_METHOD",
|
||||
" private void repeatedTest() {}",
|
||||
"",
|
||||
" private void unannotatedMethod() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMethodSourceFactoryNames() {
|
||||
CompilationTestHelper.newInstance(MethodSourceFactoryNamesTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" @MethodSource",
|
||||
" // BUG: Diagnostic contains: [matchingMethodSource]",
|
||||
" void matchingMethodSource(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource()",
|
||||
" // BUG: Diagnostic contains: [matchingMethodSourceWithParens]",
|
||||
" void matchingMethodSourceWithParens(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource(\"\")",
|
||||
" // BUG: Diagnostic contains: [matchingMethodSourceMadeExplicit]",
|
||||
" void matchingMethodSourceMadeExplicit(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource({\"\"})",
|
||||
" // BUG: Diagnostic contains: [matchingMethodSourceMadeExplicitWithParens]",
|
||||
" void matchingMethodSourceMadeExplicitWithParens(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource({})",
|
||||
" // BUG: Diagnostic contains: []",
|
||||
" void noMethodSources(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource(\"myValueFactory\")",
|
||||
" // BUG: Diagnostic contains: [myValueFactory]",
|
||||
" void singleCustomMethodSource(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource({\"firstValueFactory\", \"secondValueFactory\"})",
|
||||
" // BUG: Diagnostic contains: [firstValueFactory, secondValueFactory]",
|
||||
" void twoCustomMethodSources(boolean b) {}",
|
||||
"",
|
||||
" @MethodSource({\"myValueFactory\", \"\"})",
|
||||
" // BUG: Diagnostic contains: [myValueFactory, customAndMatchingMethodSources]",
|
||||
" void customAndMatchingMethodSources(boolean b) {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags methods matched by {@link Matcher}s of {@link MethodTree}s
|
||||
* exposed by {@link MoreJUnitMatchers}.
|
||||
*/
|
||||
@BugPattern(summary = "Interacts with `MoreJUnitMatchers` for testing purposes", severity = ERROR)
|
||||
public static final class MethodMatchersTestChecker extends BugChecker
|
||||
implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final ImmutableMap<String, Matcher<MethodTree>> METHOD_MATCHERS =
|
||||
ImmutableMap.of(
|
||||
"TEST_METHOD", TEST_METHOD,
|
||||
"HAS_METHOD_SOURCE", HAS_METHOD_SOURCE,
|
||||
"SETUP_OR_TEARDOWN_METHOD", SETUP_OR_TEARDOWN_METHOD);
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
ImmutableSet<String> matches =
|
||||
METHOD_MATCHERS.entrySet().stream()
|
||||
.filter(e -> e.getValue().matches(tree, state))
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(toImmutableSet());
|
||||
|
||||
return matches.isEmpty()
|
||||
? Description.NO_MATCH
|
||||
: buildDescription(tree).setMessage(String.join(", ", matches)).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags methods with a JUnit {@code @MethodSource} annotation by
|
||||
* enumerating the associated value factory method names.
|
||||
*/
|
||||
@BugPattern(summary = "Interacts with `MoreJUnitMatchers` for testing purposes", severity = ERROR)
|
||||
public static final class MethodSourceFactoryNamesTestChecker extends BugChecker
|
||||
implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
AnnotationTree annotation =
|
||||
Iterables.getOnlyElement(HAS_METHOD_SOURCE.multiMatchResult(tree, state).matchingNodes());
|
||||
|
||||
return buildDescription(tree)
|
||||
.setMessage(MoreJUnitMatchers.getMethodSourceFactoryNames(annotation, tree).toString())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MoreMatchersTest {
|
||||
@Test
|
||||
void hasMetaAnnotation() {
|
||||
CompilationTestHelper.newInstance(TestMatcher.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.RepeatedTest;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.api.TestTemplate;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class A {",
|
||||
" void negative1() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void negative2() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" void negative3() {}",
|
||||
"",
|
||||
" @TestTemplate",
|
||||
" void negative4() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @ParameterizedTest",
|
||||
" void positive1() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @RepeatedTest(2)",
|
||||
" void positive2() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasMetaAnnotation(String)} . */
|
||||
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
|
||||
public static final class TestMatcher extends BugChecker implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<AnnotationTree> DELEGATE =
|
||||
MoreMatchers.hasMetaAnnotation("org.junit.jupiter.api.TestTemplate");
|
||||
|
||||
@Override
|
||||
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
|
||||
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,46 @@ import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MoreTypesTest {
|
||||
private static final ImmutableSet<Supplier<Type>> TYPES =
|
||||
ImmutableSet.of(
|
||||
// Invalid types.
|
||||
type("java.lang.Nonexistent"),
|
||||
generic(type("java.util.Integer"), unbound()),
|
||||
// Valid types.
|
||||
type("java.lang.String"),
|
||||
type("java.lang.Number"),
|
||||
superOf(type("java.lang.Number")),
|
||||
subOf(type("java.lang.Number")),
|
||||
type("java.lang.Integer"),
|
||||
superOf(type("java.lang.Integer")),
|
||||
subOf(type("java.lang.Integer")),
|
||||
type("java.util.Optional"),
|
||||
raw(type("java.util.Optional")),
|
||||
generic(type("java.util.Optional"), unbound()),
|
||||
generic(type("java.util.Optional"), type("java.lang.Number")),
|
||||
type("java.util.Collection"),
|
||||
raw(type("java.util.Collection")),
|
||||
generic(type("java.util.Collection"), unbound()),
|
||||
generic(type("java.util.Collection"), type("java.lang.Number")),
|
||||
generic(type("java.util.Collection"), superOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.Collection"), subOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.Collection"), type("java.lang.Integer")),
|
||||
generic(type("java.util.Collection"), superOf(type("java.lang.Integer"))),
|
||||
generic(type("java.util.Collection"), subOf(type("java.lang.Integer"))),
|
||||
type("java.util.List"),
|
||||
raw(type("java.util.List")),
|
||||
generic(type("java.util.List"), unbound()),
|
||||
generic(type("java.util.List"), type("java.lang.Number")),
|
||||
generic(type("java.util.List"), superOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.List"), subOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.List"), type("java.lang.Integer")),
|
||||
generic(type("java.util.List"), superOf(type("java.lang.Integer"))),
|
||||
generic(type("java.util.List"), subOf(type("java.lang.Integer"))),
|
||||
generic(
|
||||
type("java.util.Map"),
|
||||
type("java.lang.String"),
|
||||
subOf(generic(type("java.util.Collection"), superOf(type("java.lang.Short"))))));
|
||||
|
||||
@Test
|
||||
void matcher() {
|
||||
CompilationTestHelper.newInstance(SubtypeFlagger.class, getClass())
|
||||
@@ -119,8 +159,8 @@ final class MoreTypesTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags method invocations that are a subtype of any type defined by
|
||||
* {@link #getTestTypes()}.
|
||||
* A {@link BugChecker} that flags method invocations that are a subtype of any type contained in
|
||||
* {@link #TYPES}.
|
||||
*/
|
||||
@BugPattern(summary = "Flags invocations of methods with select return types", severity = ERROR)
|
||||
public static final class SubtypeFlagger extends BugChecker
|
||||
@@ -133,7 +173,7 @@ final class MoreTypesTest {
|
||||
|
||||
List<String> matches = new ArrayList<>();
|
||||
|
||||
for (Supplier<Type> type : getTestTypes()) {
|
||||
for (Supplier<Type> type : TYPES) {
|
||||
Type testType = type.get(state);
|
||||
if (testType != null && state.getTypes().isSubtype(treeType, testType)) {
|
||||
matches.add(Signatures.prettyType(testType));
|
||||
@@ -144,52 +184,5 @@ final class MoreTypesTest {
|
||||
? Description.NO_MATCH
|
||||
: buildDescription(tree).setMessage(matches.toString()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type suppliers under test.
|
||||
*
|
||||
* @implNote The return value of this method should not be assigned to a field, as that would
|
||||
* prevent mutations introduced by Pitest from being killed.
|
||||
*/
|
||||
private static ImmutableSet<Supplier<Type>> getTestTypes() {
|
||||
return ImmutableSet.of(
|
||||
// Invalid types.
|
||||
type("java.lang.Nonexistent"),
|
||||
generic(type("java.util.Integer"), unbound()),
|
||||
// Valid types.
|
||||
type("java.lang.String"),
|
||||
type("java.lang.Number"),
|
||||
superOf(type("java.lang.Number")),
|
||||
subOf(type("java.lang.Number")),
|
||||
type("java.lang.Integer"),
|
||||
superOf(type("java.lang.Integer")),
|
||||
subOf(type("java.lang.Integer")),
|
||||
type("java.util.Optional"),
|
||||
raw(type("java.util.Optional")),
|
||||
generic(type("java.util.Optional"), unbound()),
|
||||
generic(type("java.util.Optional"), type("java.lang.Number")),
|
||||
type("java.util.Collection"),
|
||||
raw(type("java.util.Collection")),
|
||||
generic(type("java.util.Collection"), unbound()),
|
||||
generic(type("java.util.Collection"), type("java.lang.Number")),
|
||||
generic(type("java.util.Collection"), superOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.Collection"), subOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.Collection"), type("java.lang.Integer")),
|
||||
generic(type("java.util.Collection"), superOf(type("java.lang.Integer"))),
|
||||
generic(type("java.util.Collection"), subOf(type("java.lang.Integer"))),
|
||||
type("java.util.List"),
|
||||
raw(type("java.util.List")),
|
||||
generic(type("java.util.List"), unbound()),
|
||||
generic(type("java.util.List"), type("java.lang.Number")),
|
||||
generic(type("java.util.List"), superOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.List"), subOf(type("java.lang.Number"))),
|
||||
generic(type("java.util.List"), type("java.lang.Integer")),
|
||||
generic(type("java.util.List"), superOf(type("java.lang.Integer"))),
|
||||
generic(type("java.util.List"), subOf(type("java.lang.Integer"))),
|
||||
generic(
|
||||
type("java.util.Map"),
|
||||
type("java.lang.String"),
|
||||
subOf(generic(type("java.util.Collection"), superOf(type("java.lang.Short"))))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import javax.lang.model.element.Name;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class SourceCodeTest {
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass());
|
||||
|
||||
@Test
|
||||
void deleteWithTrailingWhitespaceAnnotations() {
|
||||
refactoringTestHelper
|
||||
.addInputLines("AnnotationToBeDeleted.java", "@interface AnnotationToBeDeleted {}")
|
||||
.expectUnchanged()
|
||||
.addInputLines(
|
||||
"AnotherAnnotationToBeDeleted.java", "@interface AnotherAnnotationToBeDeleted {}")
|
||||
.expectUnchanged()
|
||||
.addInputLines(
|
||||
"AnnotationDeletions.java",
|
||||
"",
|
||||
"interface AnnotationDeletions {",
|
||||
" class SoleAnnotation {",
|
||||
" @AnnotationToBeDeleted",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class FirstAnnotation {",
|
||||
" @AnnotationToBeDeleted",
|
||||
" @Deprecated",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MiddleAnnotation {",
|
||||
" @Deprecated",
|
||||
" @AnnotationToBeDeleted",
|
||||
" @SuppressWarnings(\"foo\")",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class LastAnnotation {",
|
||||
" @Deprecated",
|
||||
" @AnnotationToBeDeleted",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MultipleAnnotations {",
|
||||
" @AnnotationToBeDeleted",
|
||||
" @AnotherAnnotationToBeDeleted",
|
||||
" @Deprecated",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"AnnotationDeletions.java",
|
||||
"",
|
||||
"interface AnnotationDeletions {",
|
||||
" class SoleAnnotation {",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class FirstAnnotation {",
|
||||
" @Deprecated",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MiddleAnnotation {",
|
||||
" @Deprecated",
|
||||
" @SuppressWarnings(\"foo\")",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class LastAnnotation {",
|
||||
" @Deprecated",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MultipleAnnotations {",
|
||||
" @Deprecated",
|
||||
" void m() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteWithTrailingWhitespaceMethods() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"MethodDeletions.java",
|
||||
"",
|
||||
"interface MethodDeletions {",
|
||||
" class SoleMethod {",
|
||||
" void methodToBeDeleted() {}",
|
||||
" }",
|
||||
"",
|
||||
" class FirstMethod {",
|
||||
" void methodToBeDeleted() {}",
|
||||
"",
|
||||
" void finalMethod() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MiddleMethod {",
|
||||
" void initialMethod() {}",
|
||||
"",
|
||||
" void methodToBeDeleted() {}",
|
||||
"",
|
||||
" void finalMethod() {}",
|
||||
" }",
|
||||
"",
|
||||
" class LastMethod {",
|
||||
" void initialMethod() {}",
|
||||
"",
|
||||
" void methodToBeDeleted() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MultipleMethods {",
|
||||
" void method1ToBeDeleted() {}",
|
||||
"",
|
||||
" void method2ToBeDeleted() {}",
|
||||
"",
|
||||
" void middleMethod() {}",
|
||||
"",
|
||||
" void method3ToBeDeleted() {}",
|
||||
"",
|
||||
" void method4ToBeDeleted() {}",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"MethodDeletions.java",
|
||||
"",
|
||||
"interface MethodDeletions {",
|
||||
" class SoleMethod {}",
|
||||
"",
|
||||
" class FirstMethod {",
|
||||
" void finalMethod() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MiddleMethod {",
|
||||
" void initialMethod() {}",
|
||||
"",
|
||||
" void finalMethod() {}",
|
||||
" }",
|
||||
"",
|
||||
" class LastMethod {",
|
||||
" void initialMethod() {}",
|
||||
" }",
|
||||
"",
|
||||
" class MultipleMethods {",
|
||||
" void middleMethod() {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that uses {@link SourceCode#deleteWithTrailingWhitespace(Tree,
|
||||
* VisitorState)} to suggest the deletion of annotations and methods with a name containing
|
||||
* {@value DELETION_MARKER}.
|
||||
*/
|
||||
@BugPattern(severity = ERROR, summary = "Interacts with `SourceCode` for testing purposes")
|
||||
public static final class TestChecker extends BugChecker
|
||||
implements AnnotationTreeMatcher, MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String DELETION_MARKER = "ToBeDeleted";
|
||||
|
||||
@Override
|
||||
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
|
||||
return match(
|
||||
tree,
|
||||
ASTHelpers.getAnnotationMirror(tree).getAnnotationType().asElement().getSimpleName(),
|
||||
state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
return match(tree, tree.getName(), state);
|
||||
}
|
||||
|
||||
private Description match(Tree tree, Name name, VisitorState state) {
|
||||
return name.toString().contains(DELETION_MARKER)
|
||||
? describeMatch(tree, SourceCode.deleteWithTrailingWhitespace(tree, state))
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,10 +50,8 @@ final class RefasterRulesTest {
|
||||
ImmutableSortedSetRules.class,
|
||||
IntStreamRules.class,
|
||||
JUnitRules.class,
|
||||
JUnitToAssertJRules.class,
|
||||
LongStreamRules.class,
|
||||
MapEntryRules.class,
|
||||
MapRules.class,
|
||||
MockitoRules.class,
|
||||
MultimapRules.class,
|
||||
NullRules.class,
|
||||
|
||||
@@ -2,143 +2,18 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.ImmutableSortedMultiset;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
ArrayList.class,
|
||||
HashMap.class,
|
||||
HashSet.class,
|
||||
ImmutableBiMap.class,
|
||||
ImmutableList.class,
|
||||
ImmutableMultiset.class,
|
||||
ImmutableSortedMap.class,
|
||||
ImmutableSortedMultiset.class,
|
||||
ImmutableSortedSet.class,
|
||||
LinkedHashMap.class,
|
||||
TreeMap.class,
|
||||
TreeSet.class);
|
||||
}
|
||||
|
||||
void testAbstractMapAssertIsEmpty() {
|
||||
assertThat(ImmutableMap.of(1, 0)).containsExactlyEntriesOf(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(2, 0)).containsExactlyEntriesOf(ImmutableBiMap.of());
|
||||
assertThat(ImmutableMap.of(3, 0)).containsExactlyEntriesOf(ImmutableSortedMap.of());
|
||||
assertThat(ImmutableMap.of(4, 0)).containsExactlyEntriesOf(new HashMap<>());
|
||||
assertThat(ImmutableMap.of(5, 0)).containsExactlyEntriesOf(new LinkedHashMap<>());
|
||||
assertThat(ImmutableMap.of(6, 0)).containsExactlyEntriesOf(new TreeMap<>());
|
||||
assertThat(ImmutableMap.of(7, 0)).hasSameSizeAs(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(8, 0)).hasSameSizeAs(ImmutableBiMap.of());
|
||||
assertThat(ImmutableMap.of(9, 0)).hasSameSizeAs(ImmutableSortedMap.of());
|
||||
assertThat(ImmutableMap.of(10, 0)).hasSameSizeAs(new HashMap<>());
|
||||
assertThat(ImmutableMap.of(11, 0)).hasSameSizeAs(new LinkedHashMap<>());
|
||||
assertThat(ImmutableMap.of(12, 0)).hasSameSizeAs(new TreeMap<>());
|
||||
assertThat(ImmutableMap.of(13, 0)).isEqualTo(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(14, 0)).isEqualTo(ImmutableBiMap.of());
|
||||
assertThat(ImmutableMap.of(15, 0)).isEqualTo(ImmutableSortedMap.of());
|
||||
assertThat(ImmutableMap.of(16, 0)).isEqualTo(new HashMap<>());
|
||||
assertThat(ImmutableMap.of(17, 0)).isEqualTo(new LinkedHashMap<>());
|
||||
assertThat(ImmutableMap.of(18, 0)).isEqualTo(new TreeMap<>());
|
||||
assertThat(ImmutableMap.of(19, 0)).containsOnlyKeys(ImmutableList.of());
|
||||
assertThat(ImmutableMap.of(20, 0)).containsOnlyKeys(new ArrayList<>());
|
||||
assertThat(ImmutableMap.of(21, 0)).containsOnlyKeys(ImmutableSet.of());
|
||||
assertThat(ImmutableMap.of(22, 0)).containsOnlyKeys(new HashSet<>());
|
||||
assertThat(ImmutableMap.of(23, 0)).containsOnlyKeys(ImmutableSortedSet.of());
|
||||
assertThat(ImmutableMap.of(24, 0)).containsOnlyKeys(new TreeSet<>());
|
||||
assertThat(ImmutableMap.of(25, 0)).containsOnlyKeys(ImmutableMultiset.of());
|
||||
assertThat(ImmutableMap.of(26, 0)).containsOnlyKeys(ImmutableSortedMultiset.of());
|
||||
assertThat(ImmutableMap.of(27, 0)).containsExactly();
|
||||
assertThat(ImmutableMap.of(28, 0)).containsOnly();
|
||||
assertThat(ImmutableMap.of(29, 0)).containsOnlyKeys();
|
||||
}
|
||||
|
||||
void testAssertThatMapIsEmpty() {
|
||||
assertThat(ImmutableMap.of(1, 0)).hasSize(0);
|
||||
assertThat(ImmutableMap.of(2, 0).isEmpty()).isTrue();
|
||||
assertThat(ImmutableMap.of(3, 0).size()).isEqualTo(0L);
|
||||
assertThat(ImmutableMap.of(4, 0).size()).isNotPositive();
|
||||
assertThat(ImmutableMap.of(5, 0).keySet()).isEmpty();
|
||||
assertThat(ImmutableMap.of(6, 0).values()).isEmpty();
|
||||
assertThat(ImmutableMap.of(7, 0).entrySet()).isEmpty();
|
||||
}
|
||||
|
||||
ImmutableSet<MapAssert<Integer, Integer>> testAbstractMapAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 0)).isNotEqualTo(ImmutableMap.of()),
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEqualTo(ImmutableBiMap.of()),
|
||||
assertThat(ImmutableMap.of(3, 0)).isNotEqualTo(ImmutableSortedMap.of()),
|
||||
assertThat(ImmutableMap.of(4, 0)).isNotEqualTo(new HashMap<>()),
|
||||
assertThat(ImmutableMap.of(5, 0)).isNotEqualTo(new LinkedHashMap<>()),
|
||||
assertThat(ImmutableMap.of(6, 0)).isNotEqualTo(new TreeMap<>()));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatMapIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 0).isEmpty()).isFalse(),
|
||||
assertThat(ImmutableMap.of(2, 0).size()).isNotEqualTo(0),
|
||||
assertThat(ImmutableMap.of(3, 0).size()).isPositive(),
|
||||
assertThat(ImmutableMap.of(4, 0).keySet()).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(5, 0).values()).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(6, 0).entrySet()).isNotEmpty());
|
||||
}
|
||||
|
||||
MapAssert<Integer, Integer> testAbstractMapAssertContainsExactlyInAnyOrderEntriesOf() {
|
||||
AbstractMapAssert<?, ?, Integer, Integer>
|
||||
testAbstractMapAssertContainsExactlyInAnyOrderEntriesOf() {
|
||||
return assertThat(ImmutableMap.of(1, 2, 3, 4)).isEqualTo(ImmutableMap.of(1, 2, 3, 4));
|
||||
}
|
||||
|
||||
MapAssert<Integer, Integer> testAbstractMapAssertContainsExactlyEntriesOf() {
|
||||
AbstractMapAssert<?, ?, Integer, Integer> testAbstractMapAssertContainsExactlyEntriesOf() {
|
||||
return assertThat(ImmutableMap.of(1, 2))
|
||||
.containsExactlyInAnyOrderEntriesOf(ImmutableMap.of(1, 2));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatMapHasSize() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 2).size()).isEqualTo(1),
|
||||
assertThat(ImmutableMap.of(3, 4).keySet()).hasSize(1),
|
||||
assertThat(ImmutableMap.of(5, 6).values()).hasSize(1),
|
||||
assertThat(ImmutableMap.of(7, 8).entrySet()).hasSize(1));
|
||||
}
|
||||
|
||||
MapAssert<Integer, Integer> testAbstractMapAssertHasSameSizeAs() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).hasSize(ImmutableMap.of(3, 4).size());
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapContainsKey() {
|
||||
return assertThat(ImmutableMap.of(1, 2).containsKey(3)).isTrue();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapDoesNotContainKey() {
|
||||
return assertThat(ImmutableMap.of(1, 2).containsKey(3)).isFalse();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapContainsValue() {
|
||||
return assertThat(ImmutableMap.of(1, 2).containsValue(3)).isTrue();
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapDoesNotContainValue() {
|
||||
return assertThat(ImmutableMap.of(1, 2).containsValue(3)).isFalse();
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatMapContainsEntry() {
|
||||
return assertThat(ImmutableMap.of(1, 2).get(1)).isEqualTo(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,143 +2,18 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.ImmutableSortedMultiset;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class AssertJMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
ArrayList.class,
|
||||
HashMap.class,
|
||||
HashSet.class,
|
||||
ImmutableBiMap.class,
|
||||
ImmutableList.class,
|
||||
ImmutableMultiset.class,
|
||||
ImmutableSortedMap.class,
|
||||
ImmutableSortedMultiset.class,
|
||||
ImmutableSortedSet.class,
|
||||
LinkedHashMap.class,
|
||||
TreeMap.class,
|
||||
TreeSet.class);
|
||||
}
|
||||
|
||||
void testAbstractMapAssertIsEmpty() {
|
||||
assertThat(ImmutableMap.of(1, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(2, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(3, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(4, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(5, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(6, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(7, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(8, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(9, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(10, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(11, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(12, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(13, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(14, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(15, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(16, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(17, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(18, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(19, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(20, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(21, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(22, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(23, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(24, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(25, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(26, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(27, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(28, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(29, 0)).isEmpty();
|
||||
}
|
||||
|
||||
void testAssertThatMapIsEmpty() {
|
||||
assertThat(ImmutableMap.of(1, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(2, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(3, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(4, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(5, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(6, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(7, 0)).isEmpty();
|
||||
}
|
||||
|
||||
ImmutableSet<MapAssert<Integer, Integer>> testAbstractMapAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(3, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(4, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(5, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(6, 0)).isNotEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatMapIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(3, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(4, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(5, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(6, 0)).isNotEmpty());
|
||||
}
|
||||
|
||||
MapAssert<Integer, Integer> testAbstractMapAssertContainsExactlyInAnyOrderEntriesOf() {
|
||||
AbstractMapAssert<?, ?, Integer, Integer>
|
||||
testAbstractMapAssertContainsExactlyInAnyOrderEntriesOf() {
|
||||
return assertThat(ImmutableMap.of(1, 2, 3, 4))
|
||||
.containsExactlyInAnyOrderEntriesOf(ImmutableMap.of(1, 2, 3, 4));
|
||||
}
|
||||
|
||||
MapAssert<Integer, Integer> testAbstractMapAssertContainsExactlyEntriesOf() {
|
||||
AbstractMapAssert<?, ?, Integer, Integer> testAbstractMapAssertContainsExactlyEntriesOf() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).containsExactlyEntriesOf(ImmutableMap.of(1, 2));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatMapHasSize() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 2)).hasSize(1),
|
||||
assertThat(ImmutableMap.of(3, 4)).hasSize(1),
|
||||
assertThat(ImmutableMap.of(5, 6)).hasSize(1),
|
||||
assertThat(ImmutableMap.of(7, 8)).hasSize(1));
|
||||
}
|
||||
|
||||
MapAssert<Integer, Integer> testAbstractMapAssertHasSameSizeAs() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).hasSameSizeAs(ImmutableMap.of(3, 4));
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapContainsKey() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).containsKey(3);
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapDoesNotContainKey() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).doesNotContainKey(3);
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapContainsValue() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).containsValue(3);
|
||||
}
|
||||
|
||||
AbstractAssert<?, ?> testAssertThatMapDoesNotContainValue() {
|
||||
return assertThat(ImmutableMap.of(1, 2)).doesNotContainValue(3);
|
||||
}
|
||||
|
||||
AbstractObjectAssert<?, ?> testAssertThatMapContainsEntry() {
|
||||
return assertThat(ImmutableMap.of(1, 2).get(1)).isEqualTo(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,16 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.BoundType;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
@@ -19,6 +23,7 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
HashMap.class,
|
||||
HashSet.class,
|
||||
Iterables.class,
|
||||
Preconditions.class,
|
||||
@@ -38,6 +43,14 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
Map<RoundingMode, String> testCreateEnumMap() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
String testMapGetOrNull() {
|
||||
return ImmutableMap.of(1, "foo").getOrDefault("bar", null);
|
||||
}
|
||||
|
||||
ImmutableSet<BoundType> testStreamToImmutableEnumSet() {
|
||||
return Stream.of(BoundType.OPEN).collect(toImmutableSet());
|
||||
}
|
||||
@@ -82,6 +95,14 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return !ImmutableList.of().iterator().hasNext();
|
||||
}
|
||||
|
||||
Stream<String> testMapKeyStream() {
|
||||
return ImmutableMap.of("foo", 1).entrySet().stream().map(Map.Entry::getKey);
|
||||
}
|
||||
|
||||
Stream<Integer> testMapValueStream() {
|
||||
return ImmutableMap.of("foo", 1).entrySet().stream().map(Map.Entry::getValue);
|
||||
}
|
||||
|
||||
ImmutableSet<Stream<String>> testSplitToStream() {
|
||||
return ImmutableSet.of(
|
||||
Streams.stream(Splitter.on(':').split("foo")),
|
||||
|
||||
@@ -8,13 +8,18 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.BoundType;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
@@ -22,6 +27,7 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
HashMap.class,
|
||||
HashSet.class,
|
||||
Iterables.class,
|
||||
Preconditions.class,
|
||||
@@ -39,6 +45,14 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
|
||||
checkIndex(1, 2);
|
||||
}
|
||||
|
||||
Map<RoundingMode, String> testCreateEnumMap() {
|
||||
return new EnumMap<>(RoundingMode.class);
|
||||
}
|
||||
|
||||
String testMapGetOrNull() {
|
||||
return ImmutableMap.of(1, "foo").get("bar");
|
||||
}
|
||||
|
||||
ImmutableSet<BoundType> testStreamToImmutableEnumSet() {
|
||||
return Stream.of(BoundType.OPEN).collect(toImmutableEnumSet());
|
||||
}
|
||||
@@ -81,6 +95,14 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Iterables.isEmpty(ImmutableList.of());
|
||||
}
|
||||
|
||||
Stream<String> testMapKeyStream() {
|
||||
return ImmutableMap.of("foo", 1).keySet().stream();
|
||||
}
|
||||
|
||||
Stream<Integer> testMapValueStream() {
|
||||
return ImmutableMap.of("foo", 1).values().stream();
|
||||
}
|
||||
|
||||
ImmutableSet<Stream<String>> testSplitToStream() {
|
||||
return ImmutableSet.of(
|
||||
Splitter.on(':').splitToStream("foo"),
|
||||
|
||||
@@ -17,7 +17,7 @@ final class BigDecimalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(BigDecimal.valueOf(10), BigDecimal.valueOf(10L), new BigDecimal("10"));
|
||||
}
|
||||
|
||||
ImmutableSet<BigDecimal> testBigDecimalValueOf() {
|
||||
return ImmutableSet.of(new BigDecimal(2), new BigDecimal(2L), new BigDecimal(2.0));
|
||||
ImmutableSet<BigDecimal> testBigDecimalFactoryMethod() {
|
||||
return ImmutableSet.of(new BigDecimal(0), new BigDecimal(0L));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ final class BigDecimalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(BigDecimal.TEN, BigDecimal.TEN, BigDecimal.TEN);
|
||||
}
|
||||
|
||||
ImmutableSet<BigDecimal> testBigDecimalValueOf() {
|
||||
return ImmutableSet.of(BigDecimal.valueOf(2), BigDecimal.valueOf(2L), BigDecimal.valueOf(2.0));
|
||||
ImmutableSet<BigDecimal> testBigDecimalFactoryMethod() {
|
||||
return ImmutableSet.of(BigDecimal.valueOf(0), BigDecimal.valueOf(0L));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +186,4 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
? Optional.ofNullable(new LinkedList<String>().remove())
|
||||
: Optional.empty());
|
||||
}
|
||||
|
||||
void testCollectionForEach() {
|
||||
ImmutableSet.of(1).stream().forEach(String::valueOf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +136,4 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional.ofNullable(new LinkedList<String>().poll()),
|
||||
Optional.ofNullable(new LinkedList<String>().poll()));
|
||||
}
|
||||
|
||||
void testCollectionForEach() {
|
||||
ImmutableSet.of(1).forEach(String::valueOf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,42 +4,30 @@ import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
Arrays.class,
|
||||
Collections.class,
|
||||
ImmutableList.class,
|
||||
ImmutableSet.class,
|
||||
Stream.class,
|
||||
identity());
|
||||
Arrays.class, Collections.class, ImmutableList.class, ImmutableSet.class, identity());
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
String::compareTo,
|
||||
Comparator.comparing(identity()),
|
||||
Comparator.comparing(s -> s),
|
||||
Collections.<String>reverseOrder(reverseOrder()),
|
||||
Comparator.<String>reverseOrder().reversed());
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testReverseOrder() {
|
||||
return ImmutableSet.of(
|
||||
Collections.reverseOrder(),
|
||||
Collections.<String>reverseOrder(naturalOrder()),
|
||||
Comparator.<String>naturalOrder().reversed());
|
||||
Comparator<String> testReverseOrder() {
|
||||
return Comparator.<String>naturalOrder().reversed();
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testCustomComparator() {
|
||||
@@ -89,24 +77,8 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.<String>naturalOrder().thenComparing(s -> s));
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testCompareTo() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.<String>naturalOrder().compare("foo", "bar"),
|
||||
Comparator.<String>reverseOrder().compare("baz", "qux"));
|
||||
}
|
||||
|
||||
int testMinOfVarargs() {
|
||||
return Stream.of(1, 2).min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
ImmutableSet<String> testMinOfPairNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
"a".compareTo("b") <= 0 ? "a" : "b",
|
||||
"a".compareTo("b") > 0 ? "b" : "a",
|
||||
"a".compareTo("b") < 0 ? "a" : "b",
|
||||
"a".compareTo("b") >= 0 ? "b" : "a",
|
||||
Comparators.min("a", "b", naturalOrder()),
|
||||
Comparators.max("a", "b", reverseOrder()),
|
||||
Collections.min(Arrays.asList("a", "b")),
|
||||
Collections.min(ImmutableList.of("a", "b")),
|
||||
Collections.min(ImmutableSet.of("a", "b")));
|
||||
@@ -114,27 +86,13 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Object> testMinOfPairCustomOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.comparingInt(String::length).compare("a", "b") <= 0 ? "a" : "b",
|
||||
Comparator.comparingInt(String::length).compare("a", "b") > 0 ? "b" : "a",
|
||||
Comparator.comparingInt(String::length).compare("a", "b") < 0 ? "a" : "b",
|
||||
Comparator.comparingInt(String::length).compare("a", "b") >= 0 ? "b" : "a",
|
||||
Collections.min(Arrays.asList("a", "b"), (a, b) -> -1),
|
||||
Collections.min(ImmutableList.of("a", "b"), (a, b) -> 0),
|
||||
Collections.min(ImmutableSet.of("a", "b"), (a, b) -> 1));
|
||||
}
|
||||
|
||||
int testMaxOfVarargs() {
|
||||
return Stream.of(1, 2).max(naturalOrder()).orElseThrow();
|
||||
Collections.min(Arrays.asList(new Object(), new Object()), (a, b) -> -1),
|
||||
Collections.min(ImmutableList.of(new Object(), new Object()), (a, b) -> 0),
|
||||
Collections.min(ImmutableSet.of(new Object(), new Object()), (a, b) -> 1));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testMaxOfPairNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
"a".compareTo("b") >= 0 ? "a" : "b",
|
||||
"a".compareTo("b") < 0 ? "b" : "a",
|
||||
"a".compareTo("b") > 0 ? "a" : "b",
|
||||
"a".compareTo("b") <= 0 ? "b" : "a",
|
||||
Comparators.max("a", "b", naturalOrder()),
|
||||
Comparators.min("a", "b", reverseOrder()),
|
||||
Collections.max(Arrays.asList("a", "b")),
|
||||
Collections.max(ImmutableList.of("a", "b")),
|
||||
Collections.max(ImmutableSet.of("a", "b")));
|
||||
@@ -142,13 +100,9 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Object> testMaxOfPairCustomOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.comparingInt(String::length).compare("a", "b") >= 0 ? "a" : "b",
|
||||
Comparator.comparingInt(String::length).compare("a", "b") < 0 ? "b" : "a",
|
||||
Comparator.comparingInt(String::length).compare("a", "b") > 0 ? "a" : "b",
|
||||
Comparator.comparingInt(String::length).compare("a", "b") <= 0 ? "b" : "a",
|
||||
Collections.max(Arrays.asList("a", "b"), (a, b) -> -1),
|
||||
Collections.max(ImmutableList.of("a", "b"), (a, b) -> 0),
|
||||
Collections.max(ImmutableSet.of("a", "b"), (a, b) -> 1));
|
||||
Collections.max(Arrays.asList(new Object(), new Object()), (a, b) -> -1),
|
||||
Collections.max(ImmutableList.of(new Object(), new Object()), (a, b) -> 0),
|
||||
Collections.max(ImmutableSet.of(new Object(), new Object()), (a, b) -> 1));
|
||||
}
|
||||
|
||||
BinaryOperator<String> testComparatorsMin() {
|
||||
|
||||
@@ -11,29 +11,21 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
Arrays.class,
|
||||
Collections.class,
|
||||
ImmutableList.class,
|
||||
ImmutableSet.class,
|
||||
Stream.class,
|
||||
identity());
|
||||
Arrays.class, Collections.class, ImmutableList.class, ImmutableSet.class, identity());
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
naturalOrder(), naturalOrder(), naturalOrder(), naturalOrder(), naturalOrder());
|
||||
return ImmutableSet.of(naturalOrder(), naturalOrder(), naturalOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testReverseOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.reverseOrder(), Comparator.reverseOrder(), Comparator.reverseOrder());
|
||||
Comparator<String> testReverseOrder() {
|
||||
return reverseOrder();
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testCustomComparator() {
|
||||
@@ -76,64 +68,28 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.<String>naturalOrder().thenComparing(naturalOrder()));
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testCompareTo() {
|
||||
return ImmutableSet.of("foo".compareTo("bar"), "qux".compareTo("baz"));
|
||||
}
|
||||
|
||||
int testMinOfVarargs() {
|
||||
return Collections.min(Arrays.asList(1, 2), naturalOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<String> testMinOfPairNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparators.min("a", "b"),
|
||||
Comparators.min("a", "b"),
|
||||
Comparators.min("b", "a"),
|
||||
Comparators.min("b", "a"),
|
||||
Comparators.min("a", "b"),
|
||||
Comparators.min("a", "b"),
|
||||
Comparators.min("a", "b"),
|
||||
Comparators.min("a", "b"),
|
||||
Comparators.min("a", "b"));
|
||||
Comparators.min("a", "b"), Comparators.min("a", "b"), Comparators.min("a", "b"));
|
||||
}
|
||||
|
||||
ImmutableSet<Object> testMinOfPairCustomOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparators.min("a", "b", Comparator.comparingInt(String::length)),
|
||||
Comparators.min("a", "b", Comparator.comparingInt(String::length)),
|
||||
Comparators.min("b", "a", Comparator.comparingInt(String::length)),
|
||||
Comparators.min("b", "a", Comparator.comparingInt(String::length)),
|
||||
Comparators.min("a", "b", (a, b) -> -1),
|
||||
Comparators.min("a", "b", (a, b) -> 0),
|
||||
Comparators.min("a", "b", (a, b) -> 1));
|
||||
}
|
||||
|
||||
int testMaxOfVarargs() {
|
||||
return Collections.max(Arrays.asList(1, 2), naturalOrder());
|
||||
Comparators.min(new Object(), new Object(), (a, b) -> -1),
|
||||
Comparators.min(new Object(), new Object(), (a, b) -> 0),
|
||||
Comparators.min(new Object(), new Object(), (a, b) -> 1));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testMaxOfPairNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparators.max("a", "b"),
|
||||
Comparators.max("a", "b"),
|
||||
Comparators.max("b", "a"),
|
||||
Comparators.max("b", "a"),
|
||||
Comparators.max("a", "b"),
|
||||
Comparators.max("a", "b"),
|
||||
Comparators.max("a", "b"),
|
||||
Comparators.max("a", "b"),
|
||||
Comparators.max("a", "b"));
|
||||
Comparators.max("a", "b"), Comparators.max("a", "b"), Comparators.max("a", "b"));
|
||||
}
|
||||
|
||||
ImmutableSet<Object> testMaxOfPairCustomOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparators.max("a", "b", Comparator.comparingInt(String::length)),
|
||||
Comparators.max("a", "b", Comparator.comparingInt(String::length)),
|
||||
Comparators.max("b", "a", Comparator.comparingInt(String::length)),
|
||||
Comparators.max("b", "a", Comparator.comparingInt(String::length)),
|
||||
Comparators.max("a", "b", (a, b) -> -1),
|
||||
Comparators.max("a", "b", (a, b) -> 0),
|
||||
Comparators.max("a", "b", (a, b) -> 1));
|
||||
Comparators.max(new Object(), new Object(), (a, b) -> -1),
|
||||
Comparators.max(new Object(), new Object(), (a, b) -> 0),
|
||||
Comparators.max(new Object(), new Object(), (a, b) -> 1));
|
||||
}
|
||||
|
||||
BinaryOperator<String> testComparatorsMin() {
|
||||
|
||||
@@ -46,10 +46,6 @@ final class DoubleStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of(1).flatMapToDouble(v -> DoubleStream.of(v * v).flatMap(DoubleStream::of));
|
||||
}
|
||||
|
||||
DoubleStream testDoubleStreamFilterSorted() {
|
||||
return DoubleStream.of(1, 4, 3, 2).sorted().filter(d -> d % 2 == 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testDoubleStreamIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
DoubleStream.of(1).count() == 0,
|
||||
|
||||
@@ -46,10 +46,6 @@ final class DoubleStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of(1).flatMapToDouble(v -> DoubleStream.of(v * v)).flatMap(DoubleStream::of);
|
||||
}
|
||||
|
||||
DoubleStream testDoubleStreamFilterSorted() {
|
||||
return DoubleStream.of(1, 4, 3, 2).filter(d -> d % 2 == 0).sorted();
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testDoubleStreamIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
DoubleStream.of(1).findAny().isEmpty(),
|
||||
|
||||
@@ -50,10 +50,6 @@ final class IntStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of(1).flatMapToInt(v -> IntStream.of(v * v).flatMap(IntStream::of));
|
||||
}
|
||||
|
||||
IntStream testIntStreamFilterSorted() {
|
||||
return IntStream.of(1, 4, 3, 2).sorted().filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIntStreamIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
IntStream.of(1).count() == 0,
|
||||
|
||||
@@ -50,10 +50,6 @@ final class IntStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of(1).flatMapToInt(v -> IntStream.of(v * v)).flatMap(IntStream::of);
|
||||
}
|
||||
|
||||
IntStream testIntStreamFilterSorted() {
|
||||
return IntStream.of(1, 4, 3, 2).filter(i -> i % 2 == 0).sorted();
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIntStreamIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
IntStream.of(1).findAny().isEmpty(),
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
Assertions.class,
|
||||
assertDoesNotThrow(() -> null),
|
||||
assertInstanceOf(null, null),
|
||||
assertThrows(null, null),
|
||||
assertThrowsExactly(null, null),
|
||||
(Runnable) () -> assertFalse(true),
|
||||
(Runnable) () -> assertNotNull(null),
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
(Runnable) () -> assertNull(null),
|
||||
(Runnable) () -> assertSame(null, null),
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
void testThrowNewAssertionError() {
|
||||
Assertions.fail();
|
||||
}
|
||||
|
||||
Object testFailWithMessage() {
|
||||
return Assertions.fail("foo");
|
||||
}
|
||||
|
||||
Object testFailWithMessageAndThrowable() {
|
||||
return Assertions.fail("foo", new IllegalStateException());
|
||||
}
|
||||
|
||||
void testFailWithThrowable() {
|
||||
Assertions.fail(new IllegalStateException());
|
||||
}
|
||||
|
||||
void testAssertThatIsTrue() {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsTrue() {
|
||||
assertTrue(true, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsTrue() {
|
||||
assertTrue(true, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatIsFalse() {
|
||||
assertFalse(true);
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsFalse() {
|
||||
assertFalse(true, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsFalse() {
|
||||
assertFalse(true, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatIsNull() {
|
||||
assertNull(new Object());
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsNull() {
|
||||
assertNull(new Object(), "foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsNull() {
|
||||
assertNull(new Object(), () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatIsNotNull() {
|
||||
assertNotNull(new Object());
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsNotNull() {
|
||||
assertNotNull(new Object(), "foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsNotNull() {
|
||||
assertNotNull(new Object(), () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatIsSameAs() {
|
||||
assertSame("foo", "bar");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsSameAs() {
|
||||
assertSame("foo", "bar", "baz");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsSameAs() {
|
||||
assertSame("foo", "bar", () -> "baz");
|
||||
}
|
||||
|
||||
void testAssertThatIsNotSameAs() {
|
||||
assertNotSame("foo", "bar");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsNotSameAs() {
|
||||
assertNotSame("foo", "bar", "baz");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsNotSameAs() {
|
||||
assertNotSame("foo", "bar", () -> "baz");
|
||||
}
|
||||
|
||||
void testAssertThatThrownByIsExactlyInstanceOf() {
|
||||
assertThrowsExactly(IllegalStateException.class, () -> {});
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageStringIsExactlyInstanceOf() {
|
||||
assertThrowsExactly(IllegalStateException.class, () -> {}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageSupplierIsExactlyInstanceOf() {
|
||||
assertThrowsExactly(IllegalStateException.class, () -> {}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatThrownByIsInstanceOf() {
|
||||
assertThrows(IllegalStateException.class, () -> {});
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageStringIsInstanceOf() {
|
||||
assertThrows(IllegalStateException.class, () -> {}, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageSupplierIsInstanceOf() {
|
||||
assertThrows(IllegalStateException.class, () -> {}, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatCodeDoesNotThrowAnyException() {
|
||||
assertDoesNotThrow(() -> {});
|
||||
assertDoesNotThrow(() -> toString());
|
||||
}
|
||||
|
||||
void testAssertThatCodeWithFailMessageStringDoesNotThrowAnyException() {
|
||||
assertDoesNotThrow(() -> {}, "foo");
|
||||
assertDoesNotThrow(() -> toString(), "bar");
|
||||
}
|
||||
|
||||
void testAssertThatCodeWithFailMessageSupplierDoesNotThrowAnyException() {
|
||||
assertDoesNotThrow(() -> {}, () -> "foo");
|
||||
assertDoesNotThrow(() -> toString(), () -> "bar");
|
||||
}
|
||||
|
||||
void testAssertThatIsInstanceOf() {
|
||||
assertInstanceOf(Object.class, new Object());
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsInstanceOf() {
|
||||
assertInstanceOf(Object.class, new Object(), "foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsInstanceOf() {
|
||||
assertInstanceOf(Object.class, new Object(), () -> "foo");
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
Assertions.class,
|
||||
assertDoesNotThrow(() -> null),
|
||||
assertInstanceOf(null, null),
|
||||
assertThrows(null, null),
|
||||
assertThrowsExactly(null, null),
|
||||
(Runnable) () -> assertFalse(true),
|
||||
(Runnable) () -> assertNotNull(null),
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
(Runnable) () -> assertNull(null),
|
||||
(Runnable) () -> assertSame(null, null),
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
void testThrowNewAssertionError() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
Object testFailWithMessage() {
|
||||
return fail("foo");
|
||||
}
|
||||
|
||||
Object testFailWithMessageAndThrowable() {
|
||||
return fail("foo", new IllegalStateException());
|
||||
}
|
||||
|
||||
void testFailWithThrowable() {
|
||||
throw new AssertionError(new IllegalStateException());
|
||||
}
|
||||
|
||||
void testAssertThatIsTrue() {
|
||||
assertThat(true).isTrue();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsTrue() {
|
||||
assertThat(true).withFailMessage("foo").isTrue();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsTrue() {
|
||||
assertThat(true).withFailMessage(() -> "foo").isTrue();
|
||||
}
|
||||
|
||||
void testAssertThatIsFalse() {
|
||||
assertThat(true).isFalse();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsFalse() {
|
||||
assertThat(true).withFailMessage("foo").isFalse();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsFalse() {
|
||||
assertThat(true).withFailMessage(() -> "foo").isFalse();
|
||||
}
|
||||
|
||||
void testAssertThatIsNull() {
|
||||
assertThat(new Object()).isNull();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsNull() {
|
||||
assertThat(new Object()).withFailMessage("foo").isNull();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsNull() {
|
||||
assertThat(new Object()).withFailMessage(() -> "foo").isNull();
|
||||
}
|
||||
|
||||
void testAssertThatIsNotNull() {
|
||||
assertThat(new Object()).isNotNull();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsNotNull() {
|
||||
assertThat(new Object()).withFailMessage("foo").isNotNull();
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsNotNull() {
|
||||
assertThat(new Object()).withFailMessage(() -> "foo").isNotNull();
|
||||
}
|
||||
|
||||
void testAssertThatIsSameAs() {
|
||||
assertThat("bar").isSameAs("foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsSameAs() {
|
||||
assertThat("bar").withFailMessage("baz").isSameAs("foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsSameAs() {
|
||||
assertThat("bar").withFailMessage(() -> "baz").isSameAs("foo");
|
||||
}
|
||||
|
||||
void testAssertThatIsNotSameAs() {
|
||||
assertThat("bar").isNotSameAs("foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsNotSameAs() {
|
||||
assertThat("bar").withFailMessage("baz").isNotSameAs("foo");
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsNotSameAs() {
|
||||
assertThat("bar").withFailMessage(() -> "baz").isNotSameAs("foo");
|
||||
}
|
||||
|
||||
void testAssertThatThrownByIsExactlyInstanceOf() {
|
||||
assertThatThrownBy(() -> {}).isExactlyInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageStringIsExactlyInstanceOf() {
|
||||
assertThatThrownBy(() -> {})
|
||||
.withFailMessage("foo")
|
||||
.isExactlyInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageSupplierIsExactlyInstanceOf() {
|
||||
assertThatThrownBy(() -> {})
|
||||
.withFailMessage(() -> "foo")
|
||||
.isExactlyInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
void testAssertThatThrownByIsInstanceOf() {
|
||||
assertThatThrownBy(() -> {}).isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageStringIsInstanceOf() {
|
||||
assertThatThrownBy(() -> {}).withFailMessage("foo").isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
void testAssertThatThrownByWithFailMessageSupplierIsInstanceOf() {
|
||||
assertThatThrownBy(() -> {})
|
||||
.withFailMessage(() -> "foo")
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
void testAssertThatCodeDoesNotThrowAnyException() {
|
||||
assertThatCode(() -> {}).doesNotThrowAnyException();
|
||||
assertThatCode(() -> toString()).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
void testAssertThatCodeWithFailMessageStringDoesNotThrowAnyException() {
|
||||
assertThatCode(() -> {}).withFailMessage("foo").doesNotThrowAnyException();
|
||||
assertThatCode(() -> toString()).withFailMessage("bar").doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
void testAssertThatCodeWithFailMessageSupplierDoesNotThrowAnyException() {
|
||||
assertThatCode(() -> {}).withFailMessage(() -> "foo").doesNotThrowAnyException();
|
||||
assertThatCode(() -> toString()).withFailMessage(() -> "bar").doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
void testAssertThatIsInstanceOf() {
|
||||
assertThat(new Object()).isInstanceOf(Object.class);
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageStringIsInstanceOf() {
|
||||
assertThat(new Object()).withFailMessage("foo").isInstanceOf(Object.class);
|
||||
}
|
||||
|
||||
void testAssertThatWithFailMessageSupplierIsInstanceOf() {
|
||||
assertThat(new Object()).withFailMessage(() -> "foo").isInstanceOf(Object.class);
|
||||
}
|
||||
}
|
||||
@@ -50,10 +50,6 @@ final class LongStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of(1).flatMapToLong(v -> LongStream.of(v * v).flatMap(LongStream::of));
|
||||
}
|
||||
|
||||
LongStream testLongStreamFilterSorted() {
|
||||
return LongStream.of(1, 4, 3, 2).sorted().filter(l -> l % 2 == 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLongStreamIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
LongStream.of(1).count() == 0,
|
||||
|
||||
@@ -50,10 +50,6 @@ final class LongStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of(1).flatMapToLong(v -> LongStream.of(v * v)).flatMap(LongStream::of);
|
||||
}
|
||||
|
||||
LongStream testLongStreamFilterSorted() {
|
||||
return LongStream.of(1, 4, 3, 2).filter(l -> l % 2 == 0).sorted();
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLongStreamIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
LongStream.of(1).findAny().isEmpty(),
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class MapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(HashMap.class);
|
||||
}
|
||||
|
||||
Map<RoundingMode, String> testCreateEnumMap() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
String testMapGetOrNull() {
|
||||
return ImmutableMap.of(1, "foo").getOrDefault("bar", null);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testMapIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("foo", 1).keySet().isEmpty(),
|
||||
ImmutableMap.of("bar", 2).values().isEmpty(),
|
||||
ImmutableMap.of("baz", 3).entrySet().isEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testMapSize() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("foo", 1).keySet().size(),
|
||||
ImmutableMap.of("bar", 2).values().size(),
|
||||
ImmutableMap.of("baz", 3).entrySet().size());
|
||||
}
|
||||
|
||||
boolean testMapContainsKey() {
|
||||
return ImmutableMap.of("foo", 1).keySet().contains("bar");
|
||||
}
|
||||
|
||||
boolean testMapContainsValue() {
|
||||
return ImmutableMap.of("foo", 1).values().contains(2);
|
||||
}
|
||||
|
||||
Stream<String> testMapKeyStream() {
|
||||
return ImmutableMap.of("foo", 1).entrySet().stream().map(Map.Entry::getKey);
|
||||
}
|
||||
|
||||
Stream<Integer> testMapValueStream() {
|
||||
return ImmutableMap.of("foo", 1).entrySet().stream().map(Map.Entry::getValue);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class MapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(HashMap.class);
|
||||
}
|
||||
|
||||
Map<RoundingMode, String> testCreateEnumMap() {
|
||||
return new EnumMap<>(RoundingMode.class);
|
||||
}
|
||||
|
||||
String testMapGetOrNull() {
|
||||
return ImmutableMap.of(1, "foo").get("bar");
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testMapIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("foo", 1).isEmpty(),
|
||||
ImmutableMap.of("bar", 2).isEmpty(),
|
||||
ImmutableMap.of("baz", 3).isEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testMapSize() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableMap.of("foo", 1).size(),
|
||||
ImmutableMap.of("bar", 2).size(),
|
||||
ImmutableMap.of("baz", 3).size());
|
||||
}
|
||||
|
||||
boolean testMapContainsKey() {
|
||||
return ImmutableMap.of("foo", 1).containsKey("bar");
|
||||
}
|
||||
|
||||
boolean testMapContainsValue() {
|
||||
return ImmutableMap.of("foo", 1).containsValue(2);
|
||||
}
|
||||
|
||||
Stream<String> testMapKeyStream() {
|
||||
return ImmutableMap.of("foo", 1).keySet().stream();
|
||||
}
|
||||
|
||||
Stream<Integer> testMapValueStream() {
|
||||
return ImmutableMap.of("foo", 1).values().stream();
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,13 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(MoreObjects.class, Optional.class);
|
||||
return ImmutableSet.of(MoreObjects.class);
|
||||
}
|
||||
|
||||
boolean testIsNull() {
|
||||
@@ -21,13 +20,8 @@ final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Objects.nonNull("foo");
|
||||
}
|
||||
|
||||
ImmutableSet<String> testRequireNonNullElse() {
|
||||
return ImmutableSet.of(
|
||||
MoreObjects.firstNonNull("foo", "bar"), Optional.ofNullable("baz").orElse("qux"));
|
||||
}
|
||||
|
||||
String testRequireNonNullElseGet() {
|
||||
return Optional.ofNullable("foo").orElseGet(() -> "bar");
|
||||
String testRequireNonNullElse() {
|
||||
return MoreObjects.firstNonNull("foo", "bar");
|
||||
}
|
||||
|
||||
long testIsNullFunction() {
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
import static java.util.Objects.requireNonNullElseGet;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(MoreObjects.class, Optional.class);
|
||||
return ImmutableSet.of(MoreObjects.class);
|
||||
}
|
||||
|
||||
boolean testIsNull() {
|
||||
@@ -24,12 +22,8 @@ final class NullRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return "foo" != null;
|
||||
}
|
||||
|
||||
ImmutableSet<String> testRequireNonNullElse() {
|
||||
return ImmutableSet.of(requireNonNullElse("foo", "bar"), requireNonNullElse("baz", "qux"));
|
||||
}
|
||||
|
||||
String testRequireNonNullElseGet() {
|
||||
return requireNonNullElseGet("foo", () -> "bar");
|
||||
String testRequireNonNullElse() {
|
||||
return requireNonNullElse("foo", "bar");
|
||||
}
|
||||
|
||||
long testIsNullFunction() {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -35,32 +33,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Mono.fromCallable(this::toString));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoEmpty() {
|
||||
return ImmutableSet.of(Mono.justOrEmpty(null), Mono.justOrEmpty(Optional.empty()));
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoJust() {
|
||||
return Mono.justOrEmpty(Optional.of(1));
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoJustOrEmpty() {
|
||||
return Mono.justOrEmpty(Optional.ofNullable(1));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Integer>> testMonoFromOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.fromCallable(() -> Optional.of(1).orElse(null)),
|
||||
Mono.fromSupplier(() -> Optional.of(2).orElse(null)));
|
||||
}
|
||||
|
||||
Optional<Mono<String>> testOptionalMapMonoJust() {
|
||||
return Optional.of("foo").map(Mono::justOrEmpty);
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoFromOptionalSwitchIfEmpty() {
|
||||
return Optional.of(1).map(Mono::just).orElse(Mono.just(2));
|
||||
}
|
||||
|
||||
Mono<Tuple2<String, Integer>> testMonoZip() {
|
||||
return Mono.just("foo").zipWith(Mono.just(1));
|
||||
}
|
||||
@@ -105,18 +83,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1, 2, 3).take(1);
|
||||
}
|
||||
|
||||
Mono<String> testMonoDefaultIfEmpty() {
|
||||
return Mono.just("foo").switchIfEmpty(Mono.just("bar"));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testFluxDefaultIfEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just("foo").switchIfEmpty(Mono.just("bar")),
|
||||
Flux.just("baz").switchIfEmpty(Flux.just("qux")));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<?>> testMonoIdentity() {
|
||||
return ImmutableSet.of(Mono.just(1).switchIfEmpty(Mono.empty()), Mono.<Void>empty().then());
|
||||
Mono<Integer> testMonoSwitchIfEmptyOfEmptyPublisher() {
|
||||
return Mono.just(1).switchIfEmpty(Mono.empty());
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxSwitchIfEmptyOfEmptyPublisher() {
|
||||
@@ -126,16 +94,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMap() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMap(Mono::just, 1),
|
||||
Flux.just(2).flatMapSequential(Mono::just, 1),
|
||||
Flux.just(3).map(Mono::just).concatMap(identity()));
|
||||
Flux.just(1).flatMap(Mono::just, 1), Flux.just(2).flatMapSequential(Mono::just, 1));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMap(Mono::just, 1, 3),
|
||||
Flux.just(2).flatMapSequential(Mono::just, 1, 4),
|
||||
Flux.just(3).map(Mono::just).concatMap(identity(), 5));
|
||||
Flux.just(1).flatMap(Mono::just, 1, 3), Flux.just(2).flatMapSequential(Mono::just, 1, 4));
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxConcatMapIterable() {
|
||||
@@ -214,19 +178,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(1).switchMap(n -> Mono.fromSupplier(() -> n * 2)));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testMonoFlux() {
|
||||
Flux<String> testMonoFlux() {
|
||||
return Flux.concat(Mono.just("foo"));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Optional<String>>> testMonoCollectToOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flatMapMany(Mono::just),
|
||||
Mono.just("bar").flatMapMany(Flux::just),
|
||||
Flux.concat(Mono.just("baz")));
|
||||
}
|
||||
|
||||
Mono<Void> testMonoThen() {
|
||||
return Mono.just("foo").flux().then();
|
||||
}
|
||||
|
||||
Mono<Optional<String>> testMonoCollectToOptional() {
|
||||
return Mono.just("foo").map(Optional::of).defaultIfEmpty(Optional.empty());
|
||||
Mono.just("foo").map(Optional::of).defaultIfEmpty(Optional.empty()),
|
||||
Mono.just("bar").map(Optional::of).switchIfEmpty(Mono.just(Optional.empty())));
|
||||
}
|
||||
|
||||
Mono<Number> testMonoCast() {
|
||||
@@ -237,14 +196,6 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1).map(Number.class::cast);
|
||||
}
|
||||
|
||||
Mono<String> testMonoFlatMap() {
|
||||
return Mono.just("foo").map(Mono::just).flatMap(identity());
|
||||
}
|
||||
|
||||
Flux<String> testMonoFlatMapMany() {
|
||||
return Mono.just("foo").map(Mono::just).flatMapMany(identity());
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testConcatMapIterableIdentity() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(ImmutableList.of("foo")).concatMap(list -> Flux.fromIterable(list)),
|
||||
@@ -332,14 +283,6 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1).onErrorReturn(IllegalArgumentException.class::isInstance, 2);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFilterSort() {
|
||||
return Flux.just(1, 4, 3, 2).sort().filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFilterSortWithComparator() {
|
||||
return Flux.just(1, 4, 3, 2).sort(reverseOrder()).filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.of(new HashMap<>()), Context.of(ImmutableMap.of()));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.MoreCollectors.toOptional;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static reactor.function.TupleUtils.function;
|
||||
@@ -38,32 +37,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Mono.fromSupplier(this::toString));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoEmpty() {
|
||||
return ImmutableSet.of(Mono.empty(), Mono.empty());
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoJust() {
|
||||
return Mono.just(1);
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoJustOrEmpty() {
|
||||
return Mono.justOrEmpty(1);
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Integer>> testMonoFromOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.defer(() -> Mono.justOrEmpty(Optional.of(1))),
|
||||
Mono.defer(() -> Mono.justOrEmpty(Optional.of(2))));
|
||||
}
|
||||
|
||||
Optional<Mono<String>> testOptionalMapMonoJust() {
|
||||
return Optional.of("foo").map(Mono::just);
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoFromOptionalSwitchIfEmpty() {
|
||||
return Mono.justOrEmpty(Optional.of(1)).switchIfEmpty(Mono.just(2));
|
||||
}
|
||||
|
||||
Mono<Tuple2<String, Integer>> testMonoZip() {
|
||||
return Mono.zip(Mono.just("foo"), Mono.just(1));
|
||||
}
|
||||
@@ -111,17 +90,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1, 2, 3).take(1, true);
|
||||
}
|
||||
|
||||
Mono<String> testMonoDefaultIfEmpty() {
|
||||
return Mono.just("foo").defaultIfEmpty("bar");
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testFluxDefaultIfEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just("foo").defaultIfEmpty("bar"), Flux.just("baz").defaultIfEmpty("qux"));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<?>> testMonoIdentity() {
|
||||
return ImmutableSet.of(Mono.just(1), Mono.<Void>empty());
|
||||
Mono<Integer> testMonoSwitchIfEmptyOfEmptyPublisher() {
|
||||
return Mono.just(1);
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxSwitchIfEmptyOfEmptyPublisher() {
|
||||
@@ -129,17 +99,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMap() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMap(Mono::just),
|
||||
Flux.just(2).concatMap(Mono::just),
|
||||
Flux.just(3).concatMap(Mono::just));
|
||||
return ImmutableSet.of(Flux.just(1).concatMap(Mono::just), Flux.just(2).concatMap(Mono::just));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMap(Mono::just, 3),
|
||||
Flux.just(2).concatMap(Mono::just, 4),
|
||||
Flux.just(3).concatMap(Mono::just, 5));
|
||||
Flux.just(1).concatMap(Mono::just, 3), Flux.just(2).concatMap(Mono::just, 4));
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxConcatMapIterable() {
|
||||
@@ -215,17 +180,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(1).mapNotNull(n -> n * 2));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testMonoFlux() {
|
||||
Flux<String> testMonoFlux() {
|
||||
return Mono.just("foo").flux();
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Optional<String>>> testMonoCollectToOptional() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flux(), Mono.just("bar").flux(), Mono.just("baz").flux());
|
||||
}
|
||||
|
||||
Mono<Void> testMonoThen() {
|
||||
return Mono.just("foo").then();
|
||||
}
|
||||
|
||||
Mono<Optional<String>> testMonoCollectToOptional() {
|
||||
return Mono.just("foo").flux().collect(toOptional());
|
||||
Mono.just("foo").flux().collect(toOptional()),
|
||||
Mono.just("bar").flux().collect(toOptional()));
|
||||
}
|
||||
|
||||
Mono<Number> testMonoCast() {
|
||||
@@ -236,14 +198,6 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1).cast(Number.class);
|
||||
}
|
||||
|
||||
Mono<String> testMonoFlatMap() {
|
||||
return Mono.just("foo").flatMap(Mono::just);
|
||||
}
|
||||
|
||||
Flux<String> testMonoFlatMapMany() {
|
||||
return Mono.just("foo").flatMapMany(Mono::just);
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testConcatMapIterableIdentity() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(ImmutableList.of("foo")).concatMapIterable(identity()),
|
||||
@@ -327,14 +281,6 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1).onErrorReturn(IllegalArgumentException.class, 2);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFilterSort() {
|
||||
return Flux.just(1, 4, 3, 2).filter(i -> i % 2 == 0).sort();
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFilterSortWithComparator() {
|
||||
return Flux.just(1, 4, 3, 2).filter(i -> i % 2 == 0).sort(reverseOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.empty(), Context.empty());
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Objects.class, Streams.class, not(null));
|
||||
return ImmutableSet.of(Objects.class, Streams.class, not(null), reverseOrder());
|
||||
}
|
||||
|
||||
String testJoining() {
|
||||
@@ -56,14 +56,6 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of("foo").flatMap(v -> Stream.of(v.length()).flatMap(Stream::of));
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamFilterSorted() {
|
||||
return Stream.of(1, 4, 3, 2).sorted().filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamFilterSortedWithComparator() {
|
||||
return Stream.of(1, 4, 3, 2).sorted(reverseOrder()).filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<Integer>> testStreamMapFirst() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of("foo").map(s -> s.length()).findFirst(),
|
||||
|
||||
@@ -18,7 +18,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<?> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Objects.class, Streams.class, not(null));
|
||||
return ImmutableSet.of(Objects.class, Streams.class, not(null), reverseOrder());
|
||||
}
|
||||
|
||||
String testJoining() {
|
||||
@@ -57,14 +57,6 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Stream.of("foo").flatMap(v -> Stream.of(v.length())).flatMap(Stream::of);
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamFilterSorted() {
|
||||
return Stream.of(1, 4, 3, 2).filter(i -> i % 2 == 0).sorted();
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamFilterSortedWithComparator() {
|
||||
return Stream.of(1, 4, 3, 2).filter(i -> i % 2 == 0).sorted(reverseOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<Integer>> testStreamMapFirst() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of("foo").findFirst().map(s -> s.length()),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user