-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUseDetect.ql
More file actions
65 lines (58 loc) · 1.71 KB
/
Copy pathUseDetect.ql
File metadata and controls
65 lines (58 loc) · 1.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* @name Use detect
* @description Use 'detect' instead of 'select' followed by 'first' or 'last'.
* @kind problem
* @problem.severity warning
* @id rb/use-detect
* @tags performance rubocop
* @precision high
*/
// This is an implementation of the Rubocop rule
// https://github.com/rubocop/rubocop-performance/blob/master/lib/rubocop/cop/performance/detect.rb
import codeql.ruby.AST
import codeql.ruby.CFG
import codeql.ruby.dataflow.SSA
/** A call that extracts the first or last element of a list. */
class EndCall extends MethodCall {
string detect;
EndCall() {
detect = "detect" and
(
this.getMethodName() = "first" and
this.getNumberOfArguments() = 0
or
this.getNumberOfArguments() = 1 and
this.getArgument(0).getConstantValue().isInt(0)
)
or
detect = "reverse_detect" and
(
this.getMethodName() = "last" and
this.getNumberOfArguments() = 0
or
this.getNumberOfArguments() = 1 and
this.getArgument(0).getConstantValue().isInt(-1)
)
}
string detectCall() { result = detect }
}
Expr getUniqueRead(Expr e) {
forex(CfgNode eNode | eNode.getAstNode() = e |
exists(Ssa::WriteDefinition def |
def.assigns(eNode) and
strictcount(def.getARead()) = 1 and
not def = any(Ssa::PhiNode phi).getAnInput() and
def.getARead().getAstNode() = result
)
)
}
class SelectBlock extends MethodCall {
SelectBlock() {
this.getMethodName() in ["select", "filter", "find_all"] and
exists(this.getBlock())
}
}
from EndCall call, SelectBlock selectBlock
where getUniqueRead*(selectBlock) = call.getReceiver()
select call, "Replace this call and $@ with '" + call.detectCall() + "'.", selectBlock,
"'select' call"