Skip to content

Commit 14d2ff6

Browse files
committed
Ruby: Model ActiveSupport extensions to Enumerable
1 parent ad2eaf0 commit 14d2ff6

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

ruby/ql/lib/codeql/ruby/frameworks/ActiveSupport.qll

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,70 @@ module ActiveSupport {
5656
}
5757
}
5858
}
59+
60+
/**
61+
* Extensions to the `Enumerable` module.
62+
*/
63+
module Enumerable {
64+
private class ArrayIndex extends int {
65+
ArrayIndex() { this = any(DataFlow::Content::KnownElementContent c).getIndex().getInt() }
66+
}
67+
68+
private class CompactBlankSummary extends SimpleSummarizedCallable {
69+
CompactBlankSummary() { this = "compact_blank" }
70+
71+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
72+
input = "Argument[self].Element[any]" and
73+
output = "ReturnValue.Element[?]" and
74+
preservesValue = true
75+
}
76+
}
77+
78+
private class ExcludingSummary extends SimpleSummarizedCallable {
79+
ExcludingSummary() { this = ["excluding", "without"] }
80+
81+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
82+
input = "Argument[self].Element[any]" and
83+
output = "ReturnValue.Element[?]" and
84+
preservesValue = true
85+
}
86+
}
87+
88+
private class InOrderOfSummary extends SimpleSummarizedCallable {
89+
InOrderOfSummary() { this = "in_order_of" }
90+
91+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
92+
input = "Argument[self].Element[any]" and
93+
output = "ReturnValue.Element[?]" and
94+
preservesValue = true
95+
}
96+
}
97+
98+
/**
99+
* Like `Array#push` but doesn't update the receiver.
100+
*/
101+
private class IncludingSummary extends SimpleSummarizedCallable {
102+
IncludingSummary() { this = "including" }
103+
104+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
105+
(
106+
exists(ArrayIndex i |
107+
input = "Argument[self].Element[" + i + "]" and
108+
output = "ReturnValue.Element[" + i + "]"
109+
)
110+
or
111+
input = "Argument[self].Element[?]" and
112+
output = "ReturnValue.Element[?]"
113+
or
114+
exists(int i | i in [0 .. (mc.getNumberOfArguments() - 1)] |
115+
input = "Argument[" + i + "]" and
116+
output = ["ReturnValue.Element[?]"]
117+
)
118+
) and
119+
preservesValue = true
120+
}
121+
}
122+
// TODO: index_by, index_with, pick, pluck (they require Hash dataflow)
123+
}
59124
}
60125
}

0 commit comments

Comments
 (0)