@@ -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