@@ -174,38 +174,28 @@ module Filters {
174
174
* def trace_request
175
175
* start = Time.now
176
176
* yield
177
- * Logger.info("Request took #{Time.now = start} seconds")
177
+ * Logger.info("Request took #{Time.now - start} seconds")
178
178
* end
179
179
* end
180
180
* ```
181
181
*/
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 ( ) }
197
184
198
185
/**
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 .
202
189
*/
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
+ }
204
194
205
195
/**
206
196
* Holds if this callback runs before `other`.
207
197
*/
208
- private predicate runsBefore ( Filter other , ActionControllerActionMethod action ) {
198
+ predicate runsBefore ( Filter other , ActionControllerActionMethod action ) {
209
199
other .getKind ( ) = this .getKind ( ) and
210
200
not this .skipped ( action ) and
211
201
not other .skipped ( action ) and
@@ -246,17 +236,64 @@ module Filters {
246
236
this .runsBefore ( result , action ) and
247
237
not exists ( Filter mid | this .runsBefore ( mid , action ) | mid .runsBefore ( result , action ) )
248
238
}
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 }
249
262
250
263
/**
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 .
254
267
*/
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
+ )
260
297
}
261
298
262
299
/**
@@ -269,8 +306,8 @@ module Filters {
269
306
* end
270
307
* ```
271
308
*/
272
- private predicate overridden ( ) {
273
- exists ( Filter f |
309
+ predicate overridden ( ) {
310
+ exists ( FilterImpl f |
274
311
f != this and
275
312
f .getFilterCallable ( ) = this .getFilterCallable ( ) and
276
313
f .getFilterName ( ) = this .getFilterName ( ) and
@@ -279,7 +316,7 @@ module Filters {
279
316
)
280
317
}
281
318
282
- private string getFilterName ( ) { result = this .getConstantValue ( ) .getStringlikeValue ( ) }
319
+ string getFilterName ( ) { result = this .getConstantValue ( ) .getStringlikeValue ( ) }
283
320
284
321
Callable getFilterCallable ( ) { result = call .getFilterCallable ( this .getFilterName ( ) ) }
285
322
@@ -300,77 +337,18 @@ module Filters {
300
337
* Like other filter calls, the `except` and `only` keyword arguments can be
301
338
* passed to restrict the actions that the callback is skipped for.
302
339
*/
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 ( ) }
324
342
325
343
Filter getSkippedFilter ( ActionControllerActionMethod action ) {
326
- not result instanceof SkipFilter and
327
344
action = this .getAnAction ( ) and
328
345
action = result .getAnAction ( ) and
346
+ result .getKind ( ) = this .getKind ( ) and
347
+ result .registeredBefore ( this ) and
329
348
result .getFilterCallable ( ) = this .getFilterCallable ( )
330
349
}
331
350
}
332
351
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
-
374
352
/**
375
353
* Holds if `pred` is called before `succ` in the callback chain for action `action`.
376
354
* `pred` and `succ` may be methods bound to callbacks or controller actions.
0 commit comments