@@ -114,49 +114,33 @@ class ClassList extends TClassList {
114
114
this = Empty ( ) and result = Empty ( )
115
115
}
116
116
117
- predicate legalMergeHead ( ClassObjectInternal cls ) {
118
- this .getTail ( ) .doesNotContain ( cls )
119
- or
120
- this = Empty ( )
121
- }
122
-
123
117
predicate contains ( ClassObjectInternal cls ) {
124
118
cls = this .getHead ( )
125
119
or
126
120
this .getTail ( ) .contains ( cls )
127
121
}
128
122
129
- /** Use negative formulation to avoid negative recursion */
130
- predicate doesNotContain ( ClassObjectInternal cls ) {
131
- this .relevantForContains ( cls ) and
132
- cls != this .getHead ( ) and
133
- this .getTail ( ) .doesNotContain ( cls )
134
- or
135
- this = Empty ( )
136
- }
137
-
138
- private predicate relevantForContains ( ClassObjectInternal cls ) {
139
- exists ( ClassListList list |
140
- list .getItem ( _) .getHead ( ) = cls and
141
- list .getItem ( _) = this
142
- )
143
- or
144
- exists ( ClassList l |
145
- l .relevantForContains ( cls ) and
146
- this = l .getTail ( )
123
+ pragma [ nomagic]
124
+ ClassObjectInternal findDeclaringClass ( string name ) {
125
+ exists ( ClassObjectInternal head , ClassList tail , ClassDecl decl |
126
+ this = Cons ( head , tail ) and decl = head .getClassDeclaration ( )
127
+ |
128
+ if decl .declaresAttribute ( name ) then result = head else result = tail .findDeclaringClass ( name )
147
129
)
148
130
}
149
131
150
- ClassObjectInternal findDeclaringClass ( string name ) {
151
- exists ( ClassDecl head | head = this .getHead ( ) .getClassDeclaration ( ) |
152
- if head .declaresAttribute ( name )
153
- then result = this .getHead ( )
154
- else result = this .getTail ( ) .findDeclaringClass ( name )
132
+ pragma [ noinline]
133
+ private ClassObjectInternal findDeclaringClassAttribute ( string name ) {
134
+ result = this .findDeclaringClass ( name ) and
135
+ (
136
+ exists ( any ( Builtin b ) .getMember ( name ) )
137
+ or
138
+ declaredAttributeVar ( _, name , _)
155
139
)
156
140
}
157
141
158
142
predicate lookup ( string name , ObjectInternal value , CfgOrigin origin ) {
159
- exists ( ClassObjectInternal decl | decl = this .findDeclaringClass ( name ) |
143
+ exists ( ClassObjectInternal decl | decl = this .findDeclaringClassAttribute ( name ) |
160
144
Types:: declaredAttribute ( decl , name , value , origin )
161
145
)
162
146
}
@@ -199,12 +183,18 @@ class ClassList extends TClassList {
199
183
or
200
184
this .duplicate ( n ) and result = this .deduplicate ( n + 1 )
201
185
or
202
- exists ( ClassObjectInternal cls |
203
- n = this .firstIndex ( cls ) and
204
- result = Cons ( cls , this . deduplicate ( n + 1 ) )
186
+ exists ( ClassObjectInternal cls , ClassList tail |
187
+ this .deduplicateCons ( n , cls , tail ) and
188
+ result = Cons ( cls , tail )
205
189
)
206
190
}
207
191
192
+ pragma [ nomagic]
193
+ private predicate deduplicateCons ( int n , ClassObjectInternal cls , ClassList tail ) {
194
+ n = this .firstIndex ( cls ) and
195
+ tail = this .deduplicate ( n + 1 )
196
+ }
197
+
208
198
predicate isEmpty ( ) { this = Empty ( ) }
209
199
210
200
ClassList reverse ( ) { reverse_step ( this , Empty ( ) , result ) }
@@ -273,6 +263,24 @@ private class ClassListList extends TClassListList {
273
263
result = this .getTail ( ) .getItem ( n - 1 )
274
264
}
275
265
266
+ /**
267
+ * Same as
268
+ *
269
+ * ```ql
270
+ * result = this.getItem(n) and n = this.length() - 1
271
+ * ```
272
+ *
273
+ * but avoids non-linear recursion.
274
+ */
275
+ ClassList getLastItem ( int n ) {
276
+ n = 0 and this = ConsList ( result , EmptyList ( ) )
277
+ or
278
+ exists ( ClassListList tail |
279
+ this = ConsList ( _, tail ) and
280
+ result = tail .getLastItem ( n - 1 )
281
+ )
282
+ }
283
+
276
284
private ClassObjectInternal getAHead ( ) {
277
285
result = this .getHead ( ) .getHead ( )
278
286
or
@@ -295,17 +303,26 @@ private class ClassListList extends TClassListList {
295
303
ClassObjectInternal cls , ClassList removed_head , ClassListList removed_tail , int n
296
304
) {
297
305
cls = this .bestMergeCandidate ( ) and
298
- n = this .length ( ) - 1 and
299
- removed_head = this .getItem ( n ) .removeHead ( cls ) and
306
+ removed_head = this .getLastItem ( n ) .removeHead ( cls ) and
300
307
removed_tail = EmptyList ( )
301
308
or
309
+ removed_head = this .removedClassPartsCons1 ( cls , removed_tail , n ) .removeHead ( cls )
310
+ }
311
+
312
+ pragma [ nomagic]
313
+ predicate removedClassPartsCons0 ( ClassObjectInternal cls , ClassListList removed_tail , int n ) {
302
314
exists ( ClassList prev_head , ClassListList prev_tail |
303
315
this .removedClassParts ( cls , prev_head , prev_tail , n + 1 ) and
304
- removed_head = this .getItem ( n ) .removeHead ( cls ) and
305
316
removed_tail = ConsList ( prev_head , prev_tail )
306
317
)
307
318
}
308
319
320
+ pragma [ nomagic]
321
+ ClassList removedClassPartsCons1 ( ClassObjectInternal cls , ClassListList removed_tail , int n ) {
322
+ this .removedClassPartsCons0 ( cls , removed_tail , n ) and
323
+ result = this .getItem ( n )
324
+ }
325
+
309
326
ClassListList remove ( ClassObjectInternal cls ) {
310
327
exists ( ClassList removed_head , ClassListList removed_tail |
311
328
this .removedClassParts ( cls , removed_head , removed_tail , 0 ) and
@@ -315,18 +332,34 @@ private class ClassListList extends TClassListList {
315
332
this = EmptyList ( ) and result = EmptyList ( )
316
333
}
317
334
318
- predicate legalMergeCandidate ( ClassObjectInternal cls , int n ) {
319
- cls = this .getAHead ( ) and n = this .length ( )
335
+ pragma [ nomagic]
336
+ private predicate legalMergeCandidateNonEmpty (
337
+ ClassObjectInternal cls , ClassListList remainingList , ClassList remaining
338
+ ) {
339
+ this .legalMergeCandidate ( cls , ConsList ( Cons ( _, remaining ) , remainingList ) )
320
340
or
321
- this .getItem ( n ) .legalMergeHead ( cls ) and
322
- this .legalMergeCandidate ( cls , n + 1 )
341
+ exists ( ClassObjectInternal head |
342
+ this .legalMergeCandidateNonEmpty ( cls , remainingList , Cons ( head , remaining ) ) and
343
+ cls != head
344
+ )
323
345
}
324
346
325
- predicate legalMergeCandidate ( ClassObjectInternal cls ) { this .legalMergeCandidate ( cls , 0 ) }
347
+ private predicate legalMergeCandidate ( ClassObjectInternal cls , ClassListList remaining ) {
348
+ cls = this .getAHead ( ) and remaining = this
349
+ or
350
+ this .legalMergeCandidate ( cls , ConsList ( Empty ( ) , remaining ) )
351
+ or
352
+ this .legalMergeCandidateNonEmpty ( cls , remaining , Empty ( ) )
353
+ }
326
354
355
+ pragma [ noinline]
356
+ predicate legalMergeCandidate ( ClassObjectInternal cls ) {
357
+ this .legalMergeCandidate ( cls , EmptyList ( ) )
358
+ }
359
+
360
+ pragma [ noinline]
327
361
predicate illegalMergeCandidate ( ClassObjectInternal cls ) {
328
- cls = this .getAHead ( ) and
329
- this .getItem ( _) .getTail ( ) .contains ( cls )
362
+ this .legalMergeCandidateNonEmpty ( cls , _, Cons ( cls , _) )
330
363
}
331
364
332
365
ClassObjectInternal bestMergeCandidate ( int n ) {
@@ -337,6 +370,7 @@ private class ClassListList extends TClassListList {
337
370
)
338
371
}
339
372
373
+ pragma [ noinline]
340
374
ClassObjectInternal bestMergeCandidate ( ) { result = this .bestMergeCandidate ( 0 ) }
341
375
342
376
/**
@@ -417,14 +451,25 @@ private predicate merge_step(
417
451
remaining_list = original
418
452
or
419
453
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
420
- exists ( ClassObjectInternal head , ClassList prev_reverse_mro , ClassListList prev_list |
454
+ exists ( ClassObjectInternal head , ClassList prev_reverse_mro |
455
+ merge_stepCons ( head , prev_reverse_mro , remaining_list , original ) and
456
+ reversed_mro = Cons ( head , prev_reverse_mro )
457
+ )
458
+ or
459
+ merge_step ( reversed_mro , ConsList ( Empty ( ) , remaining_list ) , original )
460
+ }
461
+
462
+ pragma [ nomagic]
463
+ private predicate merge_stepCons (
464
+ ClassObjectInternal head , ClassList prev_reverse_mro , ClassListList remaining_list ,
465
+ ClassListList original
466
+ ) {
467
+ /* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
468
+ exists ( ClassListList prev_list |
421
469
merge_step ( prev_reverse_mro , prev_list , original ) and
422
470
head = prev_list .bestMergeCandidate ( ) and
423
- reversed_mro = Cons ( head , prev_reverse_mro ) and
424
471
remaining_list = prev_list .remove ( head )
425
472
)
426
- or
427
- merge_step ( reversed_mro , ConsList ( Empty ( ) , remaining_list ) , original )
428
473
}
429
474
430
475
/* Helpers for `ClassList.reverse()` */
@@ -439,10 +484,17 @@ private predicate reverse_step(ClassList lst, ClassList remainder, ClassList rev
439
484
or
440
485
exists ( ClassObjectInternal head , ClassList tail |
441
486
reversed = Cons ( head , tail ) and
442
- reverse_step ( lst , Cons ( head , remainder ) , tail )
487
+ reverse_stepCons ( lst , remainder , head , tail )
443
488
)
444
489
}
445
490
491
+ pragma [ nomagic]
492
+ private predicate reverse_stepCons (
493
+ ClassList lst , ClassList remainder , ClassObjectInternal head , ClassList tail
494
+ ) {
495
+ reverse_step ( lst , Cons ( head , remainder ) , tail )
496
+ }
497
+
446
498
module Mro {
447
499
cached
448
500
ClassList newStyleMro ( ClassObjectInternal cls ) {
0 commit comments