Skip to content

Commit 7778524

Browse files
committed
Ruby: Refactor
1 parent 5e9210f commit 7778524

File tree

1 file changed

+73
-95
lines changed
  • ruby/ql/lib/codeql/ruby/frameworks/actioncontroller

1 file changed

+73
-95
lines changed

ruby/ql/lib/codeql/ruby/frameworks/actioncontroller/Filters.qll

Lines changed: 73 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -174,38 +174,28 @@ module Filters {
174174
* def trace_request
175175
* start = Time.now
176176
* yield
177-
* Logger.info("Request took #{Time.now = start} seconds")
177+
* Logger.info("Request took #{Time.now - start} seconds")
178178
* end
179179
* end
180180
* ```
181181
*/
182-
private class Filter extends StringlikeLiteralCfgNode {
183-
private FilterCall call;
184-
private FilterKind kind;
185-
186-
Filter() {
187-
this = call.getFilterArgument() and
188-
kind = call.getKind() and
189-
call.getMethodName() = ["", "prepend_", "append_"] + kind + "_action"
190-
}
191-
192-
predicate isPrepended() { call.getMethodName().regexpMatch("^prepend.+$") }
193-
194-
MethodCallCfgNode getCall() { result = call }
195-
196-
FilterKind getKind() { result = kind }
182+
private class Filter extends FilterImpl {
183+
Filter() { not this.isSkipFilter() }
197184

198185
/**
199-
* Holds if this callback is registered before `other`. This does not
200-
* guarantee that the callback will be executed before `other`. For example,
201-
* `after_action` callbacks are executed in reverse order.
186+
* Holds if this callback does not run for `action`. This is either because
187+
* it has been explicitly skipped by a `SkipFilter` or because a callback
188+
* with the same name is registered later one, overriding this one.
202189
*/
203-
predicate registeredBefore(Filter other) { callbackRegisteredBefore(call, _, this, other) }
190+
predicate skipped(ActionControllerActionMethod action) {
191+
this = any(SkipFilter f).getSkippedFilter(action) or
192+
this.overridden()
193+
}
204194

205195
/**
206196
* Holds if this callback runs before `other`.
207197
*/
208-
private predicate runsBefore(Filter other, ActionControllerActionMethod action) {
198+
predicate runsBefore(Filter other, ActionControllerActionMethod action) {
209199
other.getKind() = this.getKind() and
210200
not this.skipped(action) and
211201
not other.skipped(action) and
@@ -246,17 +236,64 @@ module Filters {
246236
this.runsBefore(result, action) and
247237
not exists(Filter mid | this.runsBefore(mid, action) | mid.runsBefore(result, action))
248238
}
239+
}
240+
241+
/**
242+
* Behaviour that is common to filters and `skip_*` calls.
243+
* This is separated just because when we don't want `Filter` to include `skip_*` calls.
244+
*/
245+
private class FilterImpl extends StringlikeLiteralCfgNode {
246+
private FilterCall call;
247+
private FilterKind kind;
248+
249+
FilterImpl() {
250+
this = call.getFilterArgument() and
251+
kind = call.getKind() and
252+
call.getMethodName() = ["", "prepend_", "append_", "skip_"] + kind + "_action"
253+
}
254+
255+
predicate isSkipFilter() { call.getMethodName().regexpMatch("^skip_.+$") }
256+
257+
predicate isPrepended() { call.getMethodName().regexpMatch("^prepend.+$") }
258+
259+
MethodCallCfgNode getCall() { result = call }
260+
261+
FilterKind getKind() { result = kind }
249262

250263
/**
251-
* Holds if this callback does not run for `action`. This is either because
252-
* it has been explicitly skipped by a `SkipFilter` or because a callback
253-
* with the same name is registered later one, overriding this one.
264+
* Holds if this callback is registered before `other`. This does not
265+
* guarantee that the callback will be executed before `other`. For example,
266+
* `after_action` callbacks are executed in reverse order.
254267
*/
255-
predicate skipped(ActionControllerActionMethod action) {
256-
this =
257-
any(SkipFilter f | f.getKind() = this.getKind() and this.registeredBefore(f))
258-
.getSkippedFilter(action) or
259-
this.overridden()
268+
predicate registeredBefore(FilterImpl other) {
269+
exists(FilterCall otherCall |
270+
// predCall -> call
271+
// pred -> this
272+
// succ -> other
273+
other = otherCall.getFilterArgument() and
274+
(
275+
// before_action :this, :other
276+
//
277+
// before_action :this
278+
// before_action :other
279+
this.getBasicBlock() = other.getBasicBlock() and
280+
this.getASuccessor+() = other
281+
or
282+
call.getExpr().getEnclosingModule() = otherCall.getExpr().getEnclosingModule() and
283+
this.getBasicBlock().strictlyDominates(other.getBasicBlock()) and
284+
this != other
285+
or
286+
// This callback is in a superclass of `other`'s class.
287+
//
288+
// class A
289+
// before_action :this
290+
//
291+
// class B < A
292+
// before_action :other
293+
otherCall.getExpr().getEnclosingModule().getModule() =
294+
call.getExpr().getEnclosingModule().getModule().getASubClass+()
295+
)
296+
)
260297
}
261298

262299
/**
@@ -269,8 +306,8 @@ module Filters {
269306
* end
270307
* ```
271308
*/
272-
private predicate overridden() {
273-
exists(Filter f |
309+
predicate overridden() {
310+
exists(FilterImpl f |
274311
f != this and
275312
f.getFilterCallable() = this.getFilterCallable() and
276313
f.getFilterName() = this.getFilterName() and
@@ -279,7 +316,7 @@ module Filters {
279316
)
280317
}
281318

282-
private string getFilterName() { result = this.getConstantValue().getStringlikeValue() }
319+
string getFilterName() { result = this.getConstantValue().getStringlikeValue() }
283320

284321
Callable getFilterCallable() { result = call.getFilterCallable(this.getFilterName()) }
285322

@@ -300,77 +337,18 @@ module Filters {
300337
* Like other filter calls, the `except` and `only` keyword arguments can be
301338
* passed to restrict the actions that the callback is skipped for.
302339
*/
303-
private class SkipFilter extends StringlikeLiteralCfgNode {
304-
private FilterCall call;
305-
private FilterKind kind;
306-
307-
SkipFilter() {
308-
this = call.getFilterArgument() and
309-
call.getMethodName() = "skip_" + kind + "_action"
310-
}
311-
312-
FilterKind getKind() { result = kind }
313-
314-
private string getFilterName() { result = this.getConstantValue().getStringlikeValue() }
315-
316-
Callable getFilterCallable() { result = call.getFilterCallable(this.getFilterName()) }
317-
318-
ActionControllerActionMethod getAnAction() { result = call.getAnAction() }
319-
320-
predicate registeredBefore(StringlikeLiteralCfgNode other) {
321-
(other instanceof SkipFilter or other instanceof Filter) and
322-
callbackRegisteredBefore(call, _, this, other)
323-
}
340+
private class SkipFilter extends FilterImpl {
341+
SkipFilter() { this.isSkipFilter() }
324342

325343
Filter getSkippedFilter(ActionControllerActionMethod action) {
326-
not result instanceof SkipFilter and
327344
action = this.getAnAction() and
328345
action = result.getAnAction() and
346+
result.getKind() = this.getKind() and
347+
result.registeredBefore(this) and
329348
result.getFilterCallable() = this.getFilterCallable()
330349
}
331350
}
332351

333-
/**
334-
* Holds if `predCall` (resp. `succCall`) registers or skips the callback referred to by `pred` (`succ`) and `predCall` is evaluated called before `succCall`.
335-
* Typically this means that `pred` is registered before `succ`, or `pred` is skipped before `succ`, depending on the nature of the call.
336-
* `pred` and `succ` are expected to be arguments. In the examples below, `pred` is `:foo` and `succ` is `:bar`.
337-
* ```rb
338-
* before_action :foo, :bar
339-
* skip_before_action :foo, :bar
340-
* ```
341-
* This does not guarantee that the callback referred to by `pred` will be executed before
342-
* `succ`. For example, `after_action` callbacks are executed in reverse order.
343-
*/
344-
private predicate callbackRegisteredBefore(
345-
FilterCall predCall, FilterCall succCall, StringlikeLiteralCfgNode pred,
346-
StringlikeLiteralCfgNode succ
347-
) {
348-
pred = predCall.getFilterArgument() and
349-
succ = succCall.getFilterArgument() and
350-
(
351-
// before_action :this, :other
352-
//
353-
// before_action :this
354-
// before_action :other
355-
pred.getBasicBlock() = succ.getBasicBlock() and
356-
pred.getASuccessor+() = succ
357-
or
358-
predCall.getExpr().getEnclosingModule() = succCall.getExpr().getEnclosingModule() and
359-
pred.getBasicBlock().strictlyDominates(succ.getBasicBlock()) and
360-
pred != succ
361-
or
362-
// This callback is in a superclass of `other`'s class.
363-
//
364-
// class A
365-
// before_action :this
366-
//
367-
// class B < A
368-
// before_action :other
369-
succCall.getExpr().getEnclosingModule().getModule() =
370-
predCall.getExpr().getEnclosingModule().getModule().getASubClass+()
371-
)
372-
}
373-
374352
/**
375353
* Holds if `pred` is called before `succ` in the callback chain for action `action`.
376354
* `pred` and `succ` may be methods bound to callbacks or controller actions.

0 commit comments

Comments
 (0)