summaryrefslogtreecommitdiff
path: root/errorprone/tests
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2020-10-16 16:43:29 -0600
committerJeff Sharkey <jsharkey@android.com>2020-10-20 19:58:16 -0600
commit5c46da2a14e8ec8f0f39dc7802292581f7c4593e (patch)
tree8ba22a9cceab01c53fa176d1fa934fd71c323f53 /errorprone/tests
parentc0e3a096904519657bdf808a725e61848132a7f1 (diff)
Refinement of EfficientStringsChecker.
It's okay if callers try mixing "static final" values into strings, since the compiler will inline these to avoid the StringBuilder. We also expand to catch any arguments that might be dynamically calculated, such as method invocations. Identify additional inefficient code patterns: -- Passing dynamic strings into a StringBuilder, which acquires a transparent StringBuilder for each append. -- Using "str += val;" style concatenation, which acquires a transparent StringBuilder for each append. -- Using StringBuffer which has synchronization overhead. Bug: 170978902 Test: atest error_prone_android_framework_test Change-Id: Ia3758dd55a0e6753b0cc5bc83ae8fe45b6bfde1f
Diffstat (limited to 'errorprone/tests')
-rw-r--r--errorprone/tests/java/com/google/errorprone/bugpatterns/android/EfficientStringsCheckerTest.java122
1 files changed, 122 insertions, 0 deletions
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/EfficientStringsCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/EfficientStringsCheckerTest.java
index a755564d52dd..ae9c316b8ca7 100644
--- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/EfficientStringsCheckerTest.java
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/EfficientStringsCheckerTest.java
@@ -116,4 +116,126 @@ public class EfficientStringsCheckerTest {
"}")
.doTest();
}
+
+ @Test
+ public void testPreconditions_Complex() {
+ compilationHelper
+ .addSourceFile("/android/util/Preconditions.java")
+ .addSourceLines("Example.java",
+ "import android.util.Preconditions;",
+ "public class Example {",
+ " String[] classArray = new String[] { null };",
+ " String classVar;",
+ " static final String CONST_VAR = \"baz\";",
+ " public String classMethod() { return \"baz\"; }",
+ " public static final String CONST_METHOD() { return \"baz\"; }",
+ " public void checkNotNull(Example example, Object val) {",
+ " String methodVar = \"baz\";",
+ " Preconditions.checkNotNull(val, \"foo\");",
+ " Preconditions.checkNotNull(val, (\"foo\"));",
+ " Preconditions.checkNotNull(val, classArray[0]);",
+ " Preconditions.checkNotNull(val, classVar);",
+ " Preconditions.checkNotNull(val, CONST_VAR);",
+ " Preconditions.checkNotNull(val, example.classVar);",
+ " Preconditions.checkNotNull(val, Example.CONST_VAR);",
+ " Preconditions.checkNotNull(val, methodVar);",
+ " Preconditions.checkNotNull(val, classMethod());",
+ " Preconditions.checkNotNull(val, CONST_METHOD());",
+ " Preconditions.checkNotNull(val, \"foo\" + \"bar\");",
+ " Preconditions.checkNotNull(val, (\"foo\" + \"bar\"));",
+ " // BUG: Diagnostic contains:",
+ " Preconditions.checkNotNull(val, \"foo\" + classArray[0]);",
+ " // BUG: Diagnostic contains:",
+ " Preconditions.checkNotNull(val, \"foo\" + classVar);",
+ " Preconditions.checkNotNull(val, \"foo\" + CONST_VAR);",
+ " // BUG: Diagnostic contains:",
+ " Preconditions.checkNotNull(val, \"foo\" + methodVar);",
+ " // BUG: Diagnostic contains:",
+ " Preconditions.checkNotNull(val, \"foo\" + classMethod());",
+ " // BUG: Diagnostic contains:",
+ " Preconditions.checkNotNull(val, \"foo\" + CONST_METHOD());",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testStringBuffer() {
+ compilationHelper
+ .addSourceLines("Example.java",
+ "public class Example {",
+ " public void example() {",
+ " // BUG: Diagnostic contains:",
+ " StringBuffer sb = new StringBuffer();",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testStringBuilder() {
+ compilationHelper
+ .addSourceLines("Example.java",
+ "public class Example {",
+ " StringBuilder sb = new StringBuilder();",
+ " String[] classArray = new String[] { null };",
+ " String classVar;",
+ " static final String CONST_VAR = \"baz\";",
+ " public String classMethod() { return \"baz\"; }",
+ " public static final String CONST_METHOD() { return \"baz\"; }",
+ " public void generic(Example example) {",
+ " sb.append(\"foo\");",
+ " sb.append(\"foo\" + \"bar\");",
+ " sb.append(classArray[0]);",
+ " sb.append(example.classArray[0]);",
+ " sb.append(classVar);",
+ " sb.append(CONST_VAR);",
+ " sb.append(example.classVar);",
+ " sb.append(Example.CONST_VAR);",
+ " sb.append(classMethod());",
+ " sb.append(CONST_METHOD());",
+ " }",
+ " public void string(String val) {",
+ " sb.append(\"foo\").append(val);",
+ " sb.append(\"foo\").append(val != null ? \"bar\" : \"baz\");",
+ " // BUG: Diagnostic contains:",
+ " sb.append(\"foo\" + val);",
+ " }",
+ " public void number(int val) {",
+ " sb.append(\"foo\").append(val);",
+ " sb.append(\"foo\").append(val + val);",
+ " sb.append(\"foo\").append(val > 0 ? \"bar\" : \"baz\");",
+ " // BUG: Diagnostic contains:",
+ " sb.append(\"foo\" + val);",
+ " // BUG: Diagnostic contains:",
+ " sb.append(\"foo\" + String.valueOf(val));",
+ " // BUG: Diagnostic contains:",
+ " sb.append(\"foo\" + Integer.toString(val));",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testPlusAssignment() {
+ compilationHelper
+ .addSourceLines("Example.java",
+ "public class Example {",
+ " public void string(String val) {",
+ " String s = \"foo\";",
+ " // BUG: Diagnostic contains:",
+ " s += \"bar\";",
+ " // BUG: Diagnostic contains:",
+ " s += val;",
+ " // BUG: Diagnostic contains:",
+ " s += (\"bar\" + \"baz\");",
+ " }",
+ " public void number(int val) {",
+ " int other = 42;",
+ " other += 24;",
+ " other += val;",
+ " }",
+ "}")
+ .doTest();
+ }
}