diff --git a/error-prone-contrib/pom.xml b/error-prone-contrib/pom.xml index 18dd0e6d78..75a31b47b3 100644 --- a/error-prone-contrib/pom.xml +++ b/error-prone-contrib/pom.xml @@ -176,6 +176,11 @@ mockito-core provided + + org.mongodb + mongodb-driver-core + test + org.reactivestreams reactive-streams diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MongoDBTextFilterUsage.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MongoDBTextFilterUsage.java new file mode 100644 index 0000000000..77208f673e --- /dev/null +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MongoDBTextFilterUsage.java @@ -0,0 +1,47 @@ +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.PERFORMANCE; +import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; + +/** + * A {@link BugChecker} that flags usages of MongoDB {@code $text} filter usages. + * + * @see MongoDB Text Search + */ +@AutoService(BugChecker.class) +@BugPattern( + summary = + "Avoid MongoDB's `$text` filter operator, as it can trigger heavy queries and even cause the server to run out of memory", + link = BUG_PATTERNS_BASE_URL + "MongoDBTextFilterUsage", + linkType = CUSTOM, + severity = SUGGESTION, + tags = PERFORMANCE) +public final class MongoDBTextFilterUsage extends BugChecker + implements MethodInvocationTreeMatcher { + private static final long serialVersionUID = 1L; + private static final Matcher MONGO_FILTERS_TEXT_METHOD = + staticMethod().onClass("com.mongodb.client.model.Filters").named("text"); + + /** Instantiates a new {@link MongoDBTextFilterUsage} instance. */ + public MongoDBTextFilterUsage() {} + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + return MONGO_FILTERS_TEXT_METHOD.matches(tree, state) + ? describeMatch(tree) + : Description.NO_MATCH; + } +} diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MongoDBTextFilterUsageTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MongoDBTextFilterUsageTest.java new file mode 100644 index 0000000000..ea9ca288a8 --- /dev/null +++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MongoDBTextFilterUsageTest.java @@ -0,0 +1,26 @@ +package tech.picnic.errorprone.bugpatterns; + +import com.google.errorprone.CompilationTestHelper; +import org.junit.jupiter.api.Test; + +final class MongoDBTextFilterUsageTest { + @Test + void identification() { + CompilationTestHelper.newInstance(MongoDBTextFilterUsage.class, getClass()) + .addSourceLines( + "A.java", + "import com.mongodb.client.model.Filters;", + "import com.mongodb.client.model.TextSearchOptions;", + "", + "class A {", + " void m() {", + " Filters.eq(\"foo\", \"bar\");", + " // BUG: Diagnostic contains:", + " Filters.text(\"foo\");", + " // BUG: Diagnostic contains:", + " Filters.text(\"foo\", new TextSearchOptions());", + " }", + "}") + .doTest(); + } +} diff --git a/pom.xml b/pom.xml index b8855c75ea..265360736b 100644 --- a/pom.xml +++ b/pom.xml @@ -443,6 +443,19 @@ pom import + + org.mongodb + mongodb-driver-core + 4.10.2 + + + + org.mongodb + bson-record-codec + + + org.slf4j slf4j-api