Error-prone: [InvalidPatternSyntax] Invalid syntax used for a regular expression: "." is a valid but useless regex

Created on 7 Feb 2021  ·  4Comments  ·  Source: google/error-prone

Ok, I have 2 tests here, one is using the advice of error prone, but fails, and the other passes if I turn the error prone error into a warning.

For a compile error (of course this and the rest of the output says warning that's because I switched it to test ) I get

warning: [InvalidPatternSyntax] Invalid syntax used for a regular expression: "." is a valid but useless regex
    return password.replaceAll( ".", "*" );
                              ^
    (see https://errorprone.info/bugpattern/InvalidPatternSyntax)
  Did you mean 'return password.replaceAll( "\\.", "*" );'?
1 warning

This seems overly strict, or like a false positive, as error prone even agree's it's valid, and in this case it seems to be doing exactly what I want, nothing else I tried does. Maybe my regex is too rusty (I had a problem, I used a regex, now I have 2) but this seems to be functioning correctly.

Here's the tests

package com.xenoterracide.ppm.authn;

import org.junit.jupiter.api.Test;
import org.springframework.lang.NonNull;

import static org.assertj.core.api.Assertions.assertThat;

public class AsteriskTest {

  @NonNull
  public static String replaceWithAsterisk( @NonNull String password ) {
    return password.replaceAll( ".", "*" );
  }

  @Test
  public void testReplaceWithAsterisk() {
    assertThat( replaceWithAsterisk( "" ) ).isEqualTo( "" );
    assertThat( replaceWithAsterisk( "hello" ) ).isEqualTo( "*****" );
    assertThat( replaceWithAsterisk( "To*day!" ) ).isEqualTo( "*******" );
  }
}
package com.xenoterracide.ppm.authn;

import org.junit.jupiter.api.Test;
import org.springframework.lang.NonNull;

import static org.assertj.core.api.Assertions.assertThat;

public class Asterisk2Test {

  @NonNull
  public static String replaceWithAsterisk( @NonNull String password ) {
    return password.replaceAll( "\\.", "*" );
  }

  @Test
  public void testReplaceWithAsterisk() {
    assertThat( replaceWithAsterisk( "" ) ).isEqualTo( "" );
    assertThat( replaceWithAsterisk( "hello" ) ).isEqualTo( "*****" );
    assertThat( replaceWithAsterisk( "To*day!" ) ).isEqualTo( "*******" );
  }
}

Here's what I believe to be the relevant part of the gradle config

import net.ltgt.gradle.errorprone.CheckSeverity
import net.ltgt.gradle.errorprone.errorprone
import net.ltgt.gradle.nullaway.nullaway

plugins {
  `java-library`
  id("net.ltgt.errorprone")
  id("net.ltgt.nullaway")
}

dependencies {
  errorprone("com.google.errorprone:error_prone_core:2.4.+")
  errorprone("com.uber.nullaway:nullaway:0.8.+")
}

java {
  toolchain {
    languageVersion.set(JavaLanguageVersion.of(11))
  }
}

nullaway {
  annotatedPackages.add("com.xenoterracide")
}

tasks.withType<JavaCompile>().configureEach {
  options.errorprone {
    nullaway {
      severity.set(CheckSeverity.ERROR)
      acknowledgeRestrictiveAnnotations.set(true)
      handleTestAssertionLibraries.set(true)
    }
    disableWarningsInGeneratedCode.set(true)
    warn("InvalidPatternSyntax")
Received 27 file system events since last build while watching 1 hierarchies
Virtual file system retained information about 3547 files, 254 directories and 5 missing files since last build
> Task :buildSrc:extractPrecompiledScriptPluginPlugins UP-TO-DATE
> Task :buildSrc:generateExternalPluginSpecBuilders UP-TO-DATE
> Task :buildSrc:compilePluginsBlocks UP-TO-DATE
> Task :buildSrc:generatePrecompiledScriptPluginAccessors UP-TO-DATE
> Task :buildSrc:configurePrecompiledScriptDependenciesResolver
> Task :buildSrc:generateScriptPluginAdapters UP-TO-DATE
> Task :buildSrc:compileKotlin UP-TO-DATE
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:pluginDescriptors UP-TO-DATE
> Task :buildSrc:processResources UP-TO-DATE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:inspectClassesForKotlinIC UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :buildSrc:assemble UP-TO-DATE
> Task :buildSrc:compileTestKotlin NO-SOURCE
> Task :buildSrc:pluginUnderTestMetadata UP-TO-DATE
> Task :buildSrc:compileTestJava NO-SOURCE
> Task :buildSrc:compileTestGroovy NO-SOURCE
> Task :buildSrc:processTestResources NO-SOURCE
> Task :buildSrc:testClasses UP-TO-DATE
> Task :buildSrc:test NO-SOURCE
> Task :buildSrc:validatePlugins UP-TO-DATE
> Task :buildSrc:check UP-TO-DATE
> Task :buildSrc:build UP-TO-DATE
> Task :authn:compileJava NO-SOURCE
> Task :authn:processResources NO-SOURCE
> Task :authn:classes UP-TO-DATE
> Task :authn:compileTestJava
/home/xeno/IdeaProjects/PPM/api/authn/src/test/java/com/xenoterracide/ppm/authn/AsteriskTest.java:12: warning: [InvalidPatternSyntax] Invalid syntax used for a regular expression: "." is a valid but useless regex
    return password.replaceAll( ".", "*" );
                              ^
    (see https://errorprone.info/bugpattern/InvalidPatternSyntax)
  Did you mean 'return password.replaceAll( "\\.", "*" );'?
1 warning
> Task :authn:processTestResources UP-TO-DATE
> Task :authn:testClasses
Connected to the target VM, address: 'localhost:37911', transport: 'socket'
Disconnected from the target VM, address: 'localhost:37911', transport: 'socket'
> Task :authn:test FAILED


Expecting:
 <"hello">
to be equal to:
 <"*****">
but was not.
org.opentest4j.AssertionFailedError: 
Expecting:
 <"hello">
to be equal to:
 <"*****">
but was not.
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at com.xenoterracide.ppm.authn.Asterisk2Test.testReplaceWithAsterisk(Asterisk2Test.java:18)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.base/java.lang.Thread.run(Thread.java:834)


Asterisk2Test > testReplaceWithAsterisk() STARTED
Asterisk2Test > testReplaceWithAsterisk() FAILED
    org.opentest4j.AssertionFailedError at Asterisk2Test.java:18
1 test completed, 1 failed
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':authn:test'.
> There were failing tests. See the results at: file:///home/xeno/IdeaProjects/PPM/api/authn/build/test-results/test/
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 6s
3 actionable tasks: 2 executed, 1 up-to-date
Received 0 file system events during the current build while watching 1 hierarchies
Virtual file system retains information about 3557 files, 261 directories and 5 missing files until next build

here's the resolved versions

❯ ./gradlew dependencies | grep errorprone | uniq                                                                          # api -> master + ! $
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
     |    +--- com.google.errorprone:error_prone_annotations:2.3.4
errorprone - Error Prone dependencies, will be extended by all source sets' annotationProcessor configurations
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
errorproneJavac - Error Prone Javac dependencies, will only be used when using JDK 8 (i.e. not JDK 9 or superior)
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotation:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_type_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_check_api:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotations:{strictly 2.4.0} -> 2.4.0 (c)
|    |    +--- com.google.errorprone:error_prone_annotations:2.3.4
+--- com.google.errorprone:error_prone_annotations:{strictly 2.3.4} -> 2.3.4 (c)
errorprone - Error Prone dependencies, will be extended by all source sets' annotationProcessor configurations
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotation:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_type_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_check_api:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotations:{strictly 2.4.0} -> 2.4.0 (c)
errorproneJavac - Error Prone Javac dependencies, will only be used when using JDK 8 (i.e. not JDK 9 or superior)
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotation:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_type_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_check_api:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotation:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_type_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_check_api:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotations:{strictly 2.4.0} -> 2.4.0 (c)
|    |    +--- com.google.errorprone:error_prone_annotations:2.3.4
+--- com.google.errorprone:error_prone_annotations:{strictly 2.3.4} -> 2.3.4 (c)
errorprone - Error Prone dependencies, will be extended by all source sets' annotationProcessor configurations
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotation:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_type_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_check_api:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotations:{strictly 2.4.0} -> 2.4.0 (c)
errorproneJavac - Error Prone Javac dependencies, will only be used when using JDK 8 (i.e. not JDK 9 or superior)
+--- com.google.errorprone:error_prone_core:2.4.+ -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotation:2.4.0
|    |         +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.4.0
|    +--- com.google.errorprone:error_prone_type_annotations:2.4.0
|    +--- com.google.errorprone:error_prone_check_api:2.4.0
|    |    +--- com.google.errorprone:error_prone_annotation:2.4.0 (*)
|    |    +--- com.google.errorprone:error_prone_annotations:2.4.0
|    |         \--- com.google.errorprone:error_prone_annotations:2.3.3 -> 2.4.0
|    +--- com.google.errorprone:error_prone_annotations:2.4.0
+--- com.google.errorprone:error_prone_core:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotation:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_type_annotations:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_check_api:{strictly 2.4.0} -> 2.4.0 (c)
+--- com.google.errorprone:error_prone_annotations:{strictly 2.4.0} -> 2.4.0 (c)
❯                                                                                                                          # api -> master + ! $
❯ ./gradlew --version                                                                                                      # api -> master + ! $

------------------------------------------------------------
Gradle 6.7
------------------------------------------------------------

Build time:   2020-10-14 16:13:12 UTC
Revision:     312ba9e0f4f8a02d01854d1ed743b79ed996dfd3

Kotlin:       1.3.72
Groovy:       2.5.12
Ant:          Apache Ant(TM) version 1.10.8 compiled on May 10 2020
JVM:          11.0.9.1 (AdoptOpenJDK 11.0.9.1+1)
OS:           Linux 5.10.7-3-MANJARO amd64

Most helpful comment

Note that, assuming the input to replaceWithAsterisk does not contain new lines, it could be implemented as:

  @NonNull
  public static String replaceWithAsterisk( @NonNull String password ) {
    return "*".repeat(password.codePointCount(0, password.length));
  }

or even "*".repeat(password.length) if you don't really care about Unicode surrogate pairs.

IMO, there are greater chances that people are using "." trying to match dots/periods than trying to match "everything but new lines" (which could also be expressed as "[^\\r\\n\\u0085\\u2028\\u2029]", see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html#lt and https://www.regular-expressions.info/dot.html), so I wouldn't personally change the check.

All 4 comments

Note that, assuming the input to replaceWithAsterisk does not contain new lines, it could be implemented as:

  @NonNull
  public static String replaceWithAsterisk( @NonNull String password ) {
    return "*".repeat(password.codePointCount(0, password.length));
  }

or even "*".repeat(password.length) if you don't really care about Unicode surrogate pairs.

IMO, there are greater chances that people are using "." trying to match dots/periods than trying to match "everything but new lines" (which could also be expressed as "[^\\r\\n\\u0085\\u2028\\u2029]", see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html#lt and https://www.regular-expressions.info/dot.html), so I wouldn't personally change the check.

sure, but the many ways this function could be implemented isn't why I brought this up, obviously, and it's not actually a "real" implementation for the problem. If it was a real function I wouldn't match the count, as that reveals too much. This might as well be fizzbuzz if you get my drift.

Just my opinion that it doesn't seem like InvalidPatternSyntax, I could see a separate check for IllAdvisedPatternSyntax that's set to warn (by default).

Yet, my point was that there will always be alternative implementations to using a "." regex that will undoubtedly be more performant and/or better express the intent, and that using "." has good chances to be a mistake for "\\.".

| flagged | alternative |
|-----|-----|
| str.matches(".") | str.length == 1, str.codePoints().limit(2).count() == 1, str.matches("[^\\r\\n\\u0085\\u2028\\u2029]"), etc.
| str.split(".") or str.split(".", limit) | :thinking:
| str.replaceFirst(".", r) | r + str.substring(1), str.isEmpty() ? "" : r + str.substring(1), r + str.substring(Character.charCount(str.codePointAt(0))), str.replaceFirst("[^\\r\\n\\u0085\\u2028\\u2029]", r), etc.
| str.replaceAll(".", r) | r.repeat(str.length), r.repeat(str.codePointCount(0, str.length)), str.replaceAll("[^\\r\\n\\u0085\\u2028\\u2029]", r), etc.
| Pattern.matches(".", str) | see str.matches(".")
| Splitter.onPattern(".") | :thinking:

I added a note about this in 6519ed5cf7297af17dd70c61a0717b95803fdbdd. I agree that calling "." "invalid" isn't technically correct, but discouraging this was a deliberate decision to encourage people to use clearer alternatives like the ones @tbroyer mentioned.

Was this page helpful?
0 / 5 - 0 ratings