diff options
author | Jeff Sharkey <jsharkey@android.com> | 2020-10-16 16:43:29 -0600 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2020-10-20 19:58:16 -0600 |
commit | 5c46da2a14e8ec8f0f39dc7802292581f7c4593e (patch) | |
tree | 8ba22a9cceab01c53fa176d1fa934fd71c323f53 /errorprone/tests | |
parent | c0e3a096904519657bdf808a725e61848132a7f1 (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.java | 122 |
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(); + } } |