Skip to content

Commit 489bd2a

Browse files
committed
ruby: clean up and simplify query
- remove PluckCall, this only removes 1 out of 196 results - add and clean up comments
1 parent 4892025 commit 489bd2a

File tree

1 file changed

+16
-24
lines changed

1 file changed

+16
-24
lines changed

ruby/ql/src/queries/performance/CouldBeHoisted.ql

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88
* @tags performance
99
*/
1010

11-
// Consider also Associations.
12-
// Associations are lazy-loading by default, so something like
13-
// in a loop over article do
14-
// article.book
15-
// if you have 1000 articles it will do a 1000 calls to book.
16-
// If you already did article includes book, there should be no problem.
11+
// Possible Improvements;
12+
// - Consider also Associations.
13+
// Associations are lazy-loading by default, so something like
14+
// in a loop over `article` do
15+
// `article.book`
16+
// if you have 1000 articles it will do a 1000 calls to `book`.
17+
// If you already did `article includes book`, there should be no problem.
18+
// - Consider instances of ActiveRecordInstanceMethodCall, for instance
19+
// calls to `pluck`.
1720
import ruby
1821
private import codeql.ruby.AST
1922
import codeql.ruby.ast.internal.Constant
@@ -54,18 +57,6 @@ predicate happensInInnermostLoop(LoopingCall loop, DataFlow::CallNode e) {
5457
not happensInOuterLoop(loop, e)
5558
}
5659

57-
private class PluckCall extends ActiveRecordInstanceMethodCall {
58-
PluckCall() { this.getMethodName() in ["pluck"] }
59-
60-
ActiveRecordInstance chaines() { result = getChain(this) }
61-
}
62-
63-
private ActiveRecordInstance getChain(ActiveRecordInstanceMethodCall c) {
64-
result = c.getInstance()
65-
or
66-
result = getChain(c.getInstance())
67-
}
68-
6960
// The ActiveRecord instance is used to potentially control the loop
7061
predicate usedInLoopControlGuard(ActiveRecordInstance ar, DataFlow::Node guard) {
7162
TaintTracking::localTaint(ar, guard) and
@@ -85,14 +76,15 @@ DataFlow::Node guardForLoopControl(ConditionalExpr cond, Stmt control) {
8576

8677
from LoopingCall loop, DataFlow::CallNode call
8778
where
88-
// Filter loops over constants
79+
// Disregard loops over constants
8980
not isArrayConstant(loop.getReceiver().asExpr(), _) and
90-
// Filter tests
81+
// Disregard tests
9182
not call.getLocation().getFile().getAbsolutePath().matches("%test%") and
92-
not call = any(PluckCall p).chaines() and
83+
// Disregard cases where the looping is influenced by the query result
9384
not usedInLoopControlGuard(call, _) and
85+
// Only report the inner most loop
9486
happensInInnermostLoop(loop, call) and
95-
(call instanceof ActiveRecordModelFinderCall or call instanceof PluckCall) and
96-
not call.getMethodName() in ["new", "create"] and
97-
call.getLocation().getFile().getAbsolutePath().matches(["%app/models/s%", "%app/models/e%"])
87+
// Only report calls that are likely to be expensive
88+
call instanceof ActiveRecordModelFinderCall and
89+
not call.getMethodName() in ["new", "create"]
9890
select call, "This call happens inside $@, and could be hoisted.", loop, "this loop"

0 commit comments

Comments
 (0)