@@ -8,7 +8,6 @@ private import codeql.ruby.ApiGraphs
88private import codeql.ruby.AST
99private import codeql.ruby.CFG
1010private import codeql.ruby.controlflow.CfgNodes
11- private import codeql.ruby.DataFlow
1211
1312/**
1413 * Provides classes and predicates for working with Ruby Interface (RBI) files
@@ -23,21 +22,26 @@ module Rbi {
2322 /**
2423 * A node representing a Ruby Interface (RBI) type.
2524 */
26- abstract class RbiType extends DataFlow :: Node { }
25+ abstract class RbiType extends Expr { }
2726
2827 class ConstantReadAccessAsRbiType extends RbiType {
2928 ConstantReadAccessAsRbiType ( ) {
30- this . asExpr ( ) instanceof ExprNodes :: ConstantReadAccessCfgNode
29+ this instanceof ConstantReadAccess
3130 // TODO: should this class be more restrictive?
3231 }
3332 }
3433
34+ /** A method call where the receiver is `T`. */
35+ private class MethodCallAgainstT extends MethodCall {
36+ MethodCallAgainstT ( ) { this .getReceiver ( ) .( ConstantReadAccess ) .getName ( ) = "T" }
37+ }
38+
3539 /**
3640 * A call to `T.any` - a method that takes `RbiType` parameters, and returns
3741 * a type representing the union of those types.
3842 */
39- class RbiUnionType extends RbiType , DataFlow :: CallNode {
40- RbiUnionType ( ) { this = API :: getTopLevelMember ( "T" ) . getAMethodCall ( " any") }
43+ class RbiUnionType extends RbiType , MethodCallAgainstT {
44+ RbiUnionType ( ) { this . getMethodName ( ) = " any" }
4145
4246 /**
4347 * Gets a constituent type of this type union.
@@ -48,16 +52,16 @@ module Rbi {
4852 /**
4953 * A call to `T.untyped`.
5054 */
51- class RbiUntypedType extends RbiType , DataFlow :: CallNode {
52- RbiUntypedType ( ) { this = API :: getTopLevelMember ( "T" ) . getAMethodCall ( " untyped") }
55+ class RbiUntypedType extends RbiType , MethodCallAgainstT {
56+ RbiUntypedType ( ) { this . getMethodName ( ) = " untyped" }
5357 }
5458
5559 /**
5660 * A call to `T.nilable`, creating a nilable version of the type provided as
5761 * an argument.
5862 */
59- class RbiNilableType extends RbiType , DataFlow :: CallNode {
60- RbiNilableType ( ) { this = API :: getTopLevelMember ( "T" ) . getAMethodCall ( " nilable") }
63+ class RbiNilableType extends RbiType , MethodCallAgainstT {
64+ RbiNilableType ( ) { this . getMethodName ( ) = " nilable" }
6165
6266 /** Gets the type that this may represent if not nil. */
6367 RbiType getUnderlyingType ( ) { result = this .getArgument ( 0 ) }
@@ -67,75 +71,78 @@ module Rbi {
6771 * A call to `T.type_alias`. The return value of this call can be assigned to
6872 * create a type alias.
6973 */
70- class RbiTypeAlias extends RbiType , DataFlow :: CallNode {
71- RbiTypeAlias ( ) { this = API :: getTopLevelMember ( "T" ) . getAMethodCall ( " type_alias") }
74+ class RbiTypeAlias extends RbiType , MethodCallAgainstT {
75+ RbiTypeAlias ( ) { this . getMethodName ( ) = " type_alias" }
7276
7377 /**
7478 * Gets the type aliased by this call.
7579 */
7680 RbiType getAliasedType ( ) {
77- result .asExpr ( ) = this .getBlock ( ) .asExpr ( ) .( ExprNodes:: StmtSequenceCfgNode ) .getLastStmt ( )
81+ exists ( ExprNodes:: MethodCallCfgNode n | n .getExpr ( ) = this |
82+ result = n .getBlock ( ) .( ExprNodes:: StmtSequenceCfgNode ) .getLastStmt ( ) .getExpr ( )
83+ )
7884 }
7985 }
8086
8187 /**
8288 * A call to `T.self_type`.
8389 */
84- class RbiSelfType extends RbiType , DataFlow :: CallNode {
85- RbiSelfType ( ) { this = API :: getTopLevelMember ( "T" ) . getAMethodCall ( " self_type") }
90+ class RbiSelfType extends RbiType , MethodCallAgainstT {
91+ RbiSelfType ( ) { this . getMethodName ( ) = " self_type" }
8692 }
8793
8894 /**
8995 * A call to `T.noreturn`.
9096 */
91- class RbiNoreturnType extends RbiType , DataFlow:: CallNode {
92- RbiNoreturnType ( ) { this = API:: getTopLevelMember ( "T" ) .getAMethodCall ( "noreturn" ) }
97+ class RbiNoreturnType extends RbiType , MethodCallAgainstT {
98+ RbiNoreturnType ( ) { this .getMethodName ( ) = "noreturn" }
99+ }
100+
101+ /**
102+ * A `ConstantReadAccess` where the constant is from the `T` module.
103+ */
104+ private class ConstantReadAccessFromT extends ConstantReadAccess {
105+ ConstantReadAccessFromT ( ) { this .getScopeExpr ( ) .( ConstantReadAccess ) .getName ( ) = "T" }
93106 }
94107
95108 /**
96109 * A use of `T::Boolean`.
97110 */
98- class RbiBooleanType extends RbiType {
99- RbiBooleanType ( ) { this = API :: getTopLevelMember ( "T" ) . getMember ( " Boolean") . getAUse ( ) }
111+ class RbiBooleanType extends RbiType , ConstantReadAccessFromT {
112+ RbiBooleanType ( ) { this . getName ( ) = " Boolean" }
100113 }
101114
102115 /**
103116 * A use of `T::Array`.
104117 */
105- class RbiArrayType extends RbiType {
106- RbiArrayType ( ) { this = API :: getTopLevelMember ( "T" ) . getMember ( " Array") . getAUse ( ) }
118+ class RbiArrayType extends RbiType , ConstantReadAccessFromT {
119+ RbiArrayType ( ) { this . getName ( ) = " Array" }
107120
108121 /** Gets the type of elements of this array. */
109122 RbiType getElementType ( ) {
110- exists ( DataFlow:: CallNode refNode |
111- refNode .getReceiver ( ) = this and
112- refNode .asExpr ( ) instanceof ExprNodes:: ElementReferenceCfgNode
113- |
123+ exists ( ElementReference refNode | refNode .getReceiver ( ) = this |
114124 result = refNode .getArgument ( 0 )
115125 )
116126 }
117127 }
118128
119- class RbiHashType extends RbiType {
120- RbiHashType ( ) { this = API :: getTopLevelMember ( "T" ) . getMember ( " Hash") . getAUse ( ) }
129+ class RbiHashType extends RbiType , ConstantReadAccessFromT {
130+ RbiHashType ( ) { this . getName ( ) = " Hash" }
121131
122- private DataFlow:: CallNode getRefNode ( ) {
123- result .getReceiver ( ) = this and
124- result .asExpr ( ) instanceof ExprNodes:: ElementReferenceCfgNode
125- }
132+ private ElementReference getRefNode ( ) { result .getReceiver ( ) = this }
126133
127134 /** Gets the type of keys of this hash type. */
128- DataFlow :: Node getKeyType ( ) { result = this .getRefNode ( ) .getArgument ( 0 ) }
135+ Expr getKeyType ( ) { result = this .getRefNode ( ) .getArgument ( 0 ) }
129136
130137 /** Gets the type of values of this hash type. */
131- DataFlow :: Node getValueType ( ) { result = this .getRefNode ( ) .getArgument ( 1 ) }
138+ Expr getValueType ( ) { result = this .getRefNode ( ) .getArgument ( 1 ) }
132139 }
133140
134141 /**
135142 * A call to `T.proc`. This defines a type signature for a proc or block
136143 */
137- class ProcCall extends RbiType , SignatureCall {
138- ProcCall ( ) { this = API :: getTopLevelMember ( "T" ) . getAMethodCall ( " proc") }
144+ class ProcCall extends RbiType , SignatureCall , MethodCallAgainstT {
145+ ProcCall ( ) { this . getMethodName ( ) = " proc" }
139146
140147 private ProcReturnsTypeCall getReturnsTypeCall ( ) { result .getProcCall ( ) = this }
141148
@@ -193,7 +200,7 @@ module Rbi {
193200 /**
194201 * A call that defines a type signature for a method or proc.
195202 */
196- abstract class SignatureCall extends DataFlow :: CallNode {
203+ abstract class SignatureCall extends MethodCall {
197204 /**
198205 * Gets the return type of this type signature.
199206 */
@@ -206,23 +213,23 @@ module Rbi {
206213 }
207214
208215 private predicate isMethodSignatureCallNode ( CfgNode n ) {
209- exists ( MethodSignatureCall sig | sig . asExpr ( ) = n )
216+ n . ( ExprCfgNode ) . getExpr ( ) instanceof MethodSignatureCall
210217 }
211218
212219 /**
213220 * Holds if `n` is the `i`th transitive successor node of `sigNode` where there
214221 * are no intervening nodes corresponding to `MethodSignatureCall`s.
215222 */
216- private predicate methodSignatureSuccessorNodeRanked ( MethodSignatureCall sig , CfgNode n , int i ) {
223+ private predicate methodSignatureSuccessorNodeRanked ( CfgNode sigNode , CfgNode n , int i ) {
217224 // direct successor
218225 i = 1 and
219- n = sig . asExpr ( ) .getASuccessor ( ) and
226+ n = sigNode .getASuccessor ( ) and
220227 not isMethodSignatureCallNode ( n )
221228 or
222229 // transitive successor
223230 i > 1 and
224231 exists ( CfgNode np | n = np .getASuccessor ( ) |
225- methodSignatureSuccessorNodeRanked ( sig , np , i - 1 ) and
232+ methodSignatureSuccessorNodeRanked ( sigNode , np , i - 1 ) and
226233 not isMethodSignatureCallNode ( np )
227234 )
228235 }
@@ -235,31 +242,33 @@ module Rbi {
235242
236243 private MethodParamsCall getParamsCall ( ) { result .getMethodSignatureCall ( ) = this }
237244
245+ private ExprCfgNode getCfgNode ( ) { result .getExpr ( ) = this }
246+
238247 /**
239248 * Gets the method whose type signature is defined by this call.
240249 */
241- ExprCfgNode getAssociatedMethod ( ) {
250+ MethodBase getAssociatedMethod ( ) {
242251 result =
243- min ( ExprCfgNode m , int i |
244- methodSignatureSuccessorNodeRanked ( this , m , i ) and
245- m .getExpr ( ) instanceof MethodBase
252+ min ( ExprCfgNode methodCfgNode , int i |
253+ methodSignatureSuccessorNodeRanked ( this . getCfgNode ( ) , methodCfgNode , i ) and
254+ methodCfgNode .getExpr ( ) instanceof MethodBase
246255 |
247- m order by i
248- )
256+ methodCfgNode order by i
257+ ) . getExpr ( )
249258 }
250259
251260 /**
252261 * Gets a call to `attr_reader` or `attr_accessor` where the return type of
253262 * the generated method is described by this call.
254263 */
255- ExprNodes :: MethodCallCfgNode getAssociatedAttrReaderCall ( ) {
264+ MethodCall getAssociatedAttrReaderCall ( ) {
256265 result =
257266 min ( ExprNodes:: MethodCallCfgNode c , int i |
258267 c .getExpr ( ) .getMethodName ( ) = [ "attr_reader" , "attr_accessor" ] and
259- methodSignatureSuccessorNodeRanked ( this , c , i )
268+ methodSignatureSuccessorNodeRanked ( this . getCfgNode ( ) , c , i )
260269 |
261270 c order by i
262- )
271+ ) . getExpr ( )
263272 }
264273
265274 /**
@@ -279,16 +288,15 @@ module Rbi {
279288 * - the return type of
280289 * a method.
281290 */
282- class MethodSignatureDefiningCall extends DataFlow :: CallNode {
291+ class MethodSignatureDefiningCall extends MethodCall {
283292 private MethodSignatureCall sigCall ;
284293
285294 MethodSignatureDefiningCall ( ) {
286- // TODO: avoid mapping to AST layer
287- exists ( MethodCall c | c = sigCall .getBlock ( ) .asExpr ( ) .getExpr ( ) .getAChild ( ) |
295+ exists ( MethodCall c | c = sigCall .getBlock ( ) .getAChild ( ) |
288296 // The typical pattern for the contents of a `sig` block is something
289297 // like `params(<param defs>).returns(<return type>)` - we want to
290298 // pick up both of these calls.
291- this . asExpr ( ) . getExpr ( ) = c .getReceiver * ( )
299+ this = c .getReceiver * ( )
292300 )
293301 }
294302
@@ -302,23 +310,23 @@ module Rbi {
302310 /**
303311 * A call to `params`. This defines the types of parameters to a method or proc.
304312 */
305- class ParamsCall extends DataFlow :: CallNode {
313+ class ParamsCall extends MethodCall {
306314 ParamsCall ( ) { this .getMethodName ( ) = "params" }
307315
308316 /**
309317 * Gets the type of a parameter defined by this call.
310318 */
311- ParameterType getAParameterType ( ) { result = this .getArgument ( _) . asExpr ( ) }
319+ ParameterType getAParameterType ( ) { result = this .getArgument ( _) }
312320 }
313321
314- abstract class ReturnsTypeCall extends DataFlow :: CallNode {
322+ abstract class ReturnsTypeCall extends MethodCall {
315323 abstract ReturnType getReturnType ( ) ;
316324 }
317325
318326 /**
319327 * A call to `returns`. Defines the return type of a method or proc.
320328 */
321- class ReturnsCall extends DataFlow :: CallNode {
329+ class ReturnsCall extends MethodCall {
322330 ReturnsCall ( ) { this .getMethodName ( ) = "returns" }
323331
324332 /**
@@ -335,7 +343,7 @@ module Rbi {
335343 /**
336344 * A call to `void`. Essentially a "don't-care" for the return type of a method or proc.
337345 */
338- class VoidCall extends DataFlow :: CallNode {
346+ class VoidCall extends MethodCall {
339347 VoidCall ( ) { this .getMethodName ( ) = "void" }
340348
341349 /**
@@ -361,7 +369,7 @@ module Rbi {
361369 }
362370
363371 /** A call that defines part of the type signature of a proc or block argument. */
364- class ProcSignatureDefiningCall extends DataFlow :: CallNode , RbiType {
372+ class ProcSignatureDefiningCall extends MethodCall , RbiType {
365373 private ProcCall procCall ;
366374
367375 ProcSignatureDefiningCall ( ) { this .getReceiver + ( ) = procCall }
@@ -395,23 +403,23 @@ module Rbi {
395403 /**
396404 * A pair defining the type of a parameter to a method.
397405 */
398- class ParameterType extends ExprNodes :: PairCfgNode {
406+ class ParameterType extends Pair {
399407 private RbiType t ;
400408
401- ParameterType ( ) { t . asExpr ( ) = this .getValue ( ) }
409+ ParameterType ( ) { t = this .getValue ( ) }
402410
403411 /** Gets the `RbiType` of this parameter. */
404412 RbiType getType ( ) { result = t }
405413
406414 private SignatureCall getOuterMethodSignatureCall ( ) { this = result .getAParameterType ( ) }
407415
408- private ExprCfgNode getAssociatedMethod ( ) {
416+ private MethodBase getAssociatedMethod ( ) {
409417 result = this .getOuterMethodSignatureCall ( ) .( MethodSignatureCall ) .getAssociatedMethod ( )
410418 }
411419
412420 /** Gets the parameter to which this type applies. */
413421 NamedParameter getParameter ( ) {
414- result = this .getAssociatedMethod ( ) .getExpr ( ) . ( MethodBase ) . getAParameter ( ) and
422+ result = this .getAssociatedMethod ( ) .getAParameter ( ) and
415423 result .getName ( ) = this .getKey ( ) .getConstantValue ( ) .getStringlikeValue ( )
416424 }
417425 }
0 commit comments