Skip to content

Commit 041adcd

Browse files
committed
Java: Add initial version of string replaceAll with no regex query
1 parent d2a4f1e commit 041adcd

File tree

5 files changed

+57
-0
lines changed

5 files changed

+57
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# J-STR-001: Use of `String.replaceAll` with a first argument of a non regular expression
2+
3+
Using `String.replaceAll` is less performant than `String.replace` when the first argument is not a regular expression.
4+
5+
## Overview
6+
7+
The underlying implementation of `String.replaceAll` uses `Pattern.compile` and expects a regular expression as its first argument. However in cases where the argument could be represented by just a plain `String` that does not represent an interesting regular expression, a call to `String.replace` may be more performant as it does not need to compile the regular expression.
8+
9+
## Recommendation
10+
11+
Use `String.replace` instead where a `replaceAll` call uses a trivial string as its first argument.
12+
13+
## Example
14+
15+
```java
16+
public class Test {
17+
void f() {
18+
String s1 = "test";
19+
s1 = s1.replaceAll("t", "x"); // NON_COMPLIANT
20+
s1 = s1.replaceAll(".*", "x"); // COMPLIANT
21+
}
22+
}
23+
24+
```
25+
26+
## References
27+
28+
- [String.replaceAll](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/String.html#replaceAll(java.lang.String,java.lang.String))
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @id java/string-replace-all-with-non-regex
3+
* @name J-STR-001: Use of `String#replaceAll` with a first argument of a non regular expression
4+
* @description Using `String#replaceAll` is less performant than `String#replace` when the first
5+
* argument is not a regular expression.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity recommendation
9+
* @tags performance
10+
*/
11+
12+
import java
13+
14+
from MethodCall replaceAllCall
15+
where
16+
replaceAllCall.getMethod().hasQualifiedName("java.lang", "String", "replaceAll") and
17+
//only contains characters that could be a simple string
18+
replaceAllCall.getArgument(0).(StringLiteral).getValue().regexpMatch("^[a-zA-Z0-9]+$")
19+
select replaceAllCall,
20+
"Call to 'replaceAll' uses an argument comprised of plain string characters only."
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| Test.java:4:14:4:36 | replaceAll(...) | Call to 'replaceAll' uses an argument comprised of plain string characters only. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Performance/StringReplaceAllWithNonRegex.ql
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public class Test {
2+
void f() {
3+
String s1 = "test";
4+
s1 = s1.replaceAll("t", "x"); // NON_COMPLIANT
5+
s1 = s1.replaceAll(".*", "x"); // COMPLIANT
6+
}
7+
}

0 commit comments

Comments
 (0)