-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Java: Improve concatenation in loops #16859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
| ConcatenationInLoops.java:9:4:9:10 | ...+=... | The string s is built-up in a loop: use string buffer. | | ||
| ConcatenationInLoops.java:32:6:32:12 | ...+=... | The string s is built-up in a loop: use string buffer. | | ||
| ConcatenationInLoops.java:39:4:39:12 | ...+=... | The string cs is built-up in a loop: use string buffer. | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
public class ConcatenationInLoops { | ||
private String cs = ""; | ||
|
||
public static void main(String[] args) { | ||
// Random r = 42; | ||
long start = System.currentTimeMillis(); | ||
String s = ""; | ||
for (int i = 0; i < 65536; i++) | ||
s += 42; // $ loopConcat=s | ||
System.out.println(System.currentTimeMillis() - start); // This prints roughly 4500. | ||
|
||
// r = 42; | ||
start = System.currentTimeMillis(); | ||
StringBuilder sb = new StringBuilder(); | ||
for (int i = 0; i < 65536; i++) | ||
sb.append(42);//r.nextInt(2)); | ||
s = sb.toString(); | ||
System.out.println(System.currentTimeMillis() - start); // This prints 5. | ||
|
||
|
||
String s2 = ""; | ||
for (int i = 0; i < 65536; i++) | ||
if (i > 10) { | ||
s += 42; // Will only be executed once. | ||
break; | ||
} | ||
|
||
String s3 = ""; | ||
for (int i = 0; i < 65536; i++) | ||
for (int j = 0; i < 65536; i++) | ||
if (j > 10) { | ||
s += 42; // $ loopConcat=s | ||
break; | ||
} | ||
} | ||
|
||
public void test(int bound) { | ||
if (bound > 0) { | ||
cs += "a"; // $ loopConcat=cs | ||
test(bound - 1); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Performance/ConcatenationInLoops.ql |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
testFailures | ||
failures |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import java | ||
import semmle.code.java.dataflow.DataFlow | ||
import TestUtilities.InlineExpectationsTest | ||
|
||
module TheQuery { | ||
import semmle.code.java.Type | ||
import semmle.code.java.Expr | ||
Check warningCode scanning / CodeQL Redundant import Warning test
Redundant import, the module is already imported inside
semmle.code.java.Statement Error loading related location Loading |
||
import semmle.code.java.Statement | ||
import semmle.code.java.JDK | ||
Check warningCode scanning / CodeQL Redundant import Warning test
Redundant import, the module is already imported inside
semmle.code.java.Type Error loading related location Loading |
||
|
||
/** | ||
* An assignment of the form | ||
* | ||
* ``` | ||
* v = ... + ... v ... | ||
* ``` | ||
* or | ||
* | ||
* ``` | ||
* v += ... | ||
* ``` | ||
* where `v` is a simple variable (and not, for example, | ||
* an array element). | ||
*/ | ||
Comment on lines
+11
to
+24
Check warningCode scanning / CodeQL Predicate QLDoc style. Warning test
The QLDoc for a predicate without a result should start with 'Holds'.
|
||
predicate useAndDef(Assignment a, Variable v) { | ||
a.getDest() = v.getAnAccess() and | ||
v.getType() instanceof TypeString and | ||
( | ||
a instanceof AssignAddExpr | ||
or | ||
exists(VarAccess use | use.getVariable() = v | use.getParent*() = a.getSource()) and | ||
a.getSource() instanceof AddExpr | ||
) | ||
} | ||
|
||
/** | ||
* Holds if `e` is executed often in loop `loop`. | ||
*/ | ||
predicate executedOften(Assignment a) { | ||
Check warningCode scanning / CodeQL Missing QLDoc for parameter Warning test
The QLDoc has no documentation for a, but the QLDoc mentions loop
|
||
a.getDest().getType() instanceof TypeString and | ||
exists(ControlFlowNode n | a.getControlFlowNode() = n | getADeepSuccessor(n) = n) | ||
} | ||
|
||
/** Gets a sucessor of `n`, also following function calls. */ | ||
Check warningCode scanning / CodeQL Misspelling Warning test
This comment contains the common misspelling 'sucessor', which should instead be 'successor'.
|
||
ControlFlowNode getADeepSuccessor(ControlFlowNode n) { | ||
result = n.getASuccessor+() | ||
or | ||
exists(Call c, ControlFlowNode callee | c.(Expr).getControlFlowNode() = n.getASuccessor+() | | ||
callee = c.getCallee().getBody().getControlFlowNode() and | ||
result = getADeepSuccessor(callee) | ||
) | ||
} | ||
|
||
predicate queryResult(Assignment a) { | ||
exists(Variable v | | ||
Check warningCode scanning / CodeQL Omittable 'exists' variable Warning test
This exists variable can be omitted by using a don't-care expression
in this argument Error loading related location Loading |
||
useAndDef(a, v) and | ||
executedOften(a) | ||
) | ||
} | ||
} | ||
|
||
// module Config implements DataFlow::ConfigSig { | ||
// predicate isSource(DataFlow::Node n) { n.asExpr().(MethodCall).getMethod().hasName("source") } | ||
// predicate isSink(DataFlow::Node n) { | ||
// exists(MethodCall ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument()) | ||
// } | ||
// } | ||
// module Flow = DataFlow::Global<Config>; | ||
module HasFlowTest implements TestSig { | ||
string getARelevantTag() { result = "loopConcat" } | ||
|
||
predicate hasActualResult(Location location, string element, string tag, string value) { | ||
tag = "loopConcat" and | ||
exists(Assignment a | TheQuery::queryResult(a) | | ||
location = a.getLocation() and | ||
element = a.toString() and | ||
value = a.getDest().toString() | ||
) | ||
} | ||
} | ||
|
||
import MakeTest<HasFlowTest> |
Check warning
Code scanning / CodeQL
Missing QLDoc for parameter Warning