@@ -18,8 +18,12 @@ module ActiveResource {
18
18
* An ActiveResource model class. This is any (transitive) subclass of ActiveResource.
19
19
*/
20
20
pragma [ nomagic]
21
- private API:: Node modelApiNode ( ) {
22
- result = API:: getTopLevelMember ( "ActiveResource" ) .getMember ( "Base" ) .getASubclass ( )
21
+ private API:: Node activeResourceBaseClass ( ) {
22
+ result = API:: getTopLevelMember ( "ActiveResource" ) .getMember ( "Base" )
23
+ }
24
+
25
+ private DataFlow:: ClassNode activeResourceClass ( ) {
26
+ result = activeResourceBaseClass ( ) .getADescendentModule ( )
23
27
}
24
28
25
29
/**
@@ -30,16 +34,8 @@ module ActiveResource {
30
34
* end
31
35
* ```
32
36
*/
33
- class ModelClass extends ClassDeclaration {
34
- API:: Node model ;
35
-
36
- ModelClass ( ) {
37
- model = modelApiNode ( ) and
38
- this .getSuperclassExpr ( ) = model .getAValueReachableFromSource ( ) .asExpr ( ) .getExpr ( )
39
- }
40
-
41
- /** Gets the API node for this model */
42
- API:: Node getModelApiNode ( ) { result = model }
37
+ class ModelClassNode extends DataFlow:: ClassNode {
38
+ ModelClassNode ( ) { this = activeResourceClass ( ) }
43
39
44
40
/** Gets a call to `site=`, which sets the base URL for this model. */
45
41
SiteAssignCall getASiteAssignment ( ) { result .getModelClass ( ) = this }
@@ -49,6 +45,46 @@ module ActiveResource {
49
45
c = this .getASiteAssignment ( ) and
50
46
c .disablesCertificateValidation ( )
51
47
}
48
+
49
+ /** Gets a method call on this class that returns an instance of the class. */
50
+ private DataFlow:: CallNode getAChainedCall ( ) {
51
+ result .( FindCall ) .getModelClass ( ) = this
52
+ or
53
+ result .( CreateCall ) .getModelClass ( ) = this
54
+ or
55
+ result .( CustomHttpCall ) .getModelClass ( ) = this
56
+ or
57
+ result .( CollectionCall ) .getCollection ( ) .getModelClass ( ) = this and
58
+ result .getMethodName ( ) = [ "first" , "last" ]
59
+ }
60
+
61
+ /** Gets an API node referring to an instance of this class. */
62
+ API:: Node getAnInstanceReference ( ) {
63
+ result = this .trackInstance ( )
64
+ or
65
+ result = this .getAChainedCall ( ) .track ( )
66
+ }
67
+ }
68
+
69
+ /** DEPRECATED. Use `ModelClassNode` instead. */
70
+ deprecated class ModelClass extends ClassDeclaration {
71
+ private ModelClassNode cls ;
72
+
73
+ ModelClass ( ) { this = cls .getADeclaration ( ) }
74
+
75
+ /** Gets the class for which this is a declaration. */
76
+ ModelClassNode getClassNode ( ) { result = cls }
77
+
78
+ /** Gets the API node for this class object. */
79
+ deprecated API:: Node getModelApiNode ( ) { result = cls .trackModule ( ) }
80
+
81
+ /** Gets a call to `site=`, which sets the base URL for this model. */
82
+ SiteAssignCall getASiteAssignment ( ) { result = cls .getASiteAssignment ( ) }
83
+
84
+ /** Holds if `c` sets a base URL which does not use HTTPS. */
85
+ predicate disablesCertificateValidation ( SiteAssignCall c ) {
86
+ cls .disablesCertificateValidation ( c )
87
+ }
52
88
}
53
89
54
90
/**
@@ -62,38 +98,31 @@ module ActiveResource {
62
98
* ```
63
99
*/
64
100
class ModelClassMethodCall extends DataFlow:: CallNode {
65
- API :: Node model ;
101
+ private ModelClassNode cls ;
66
102
67
- ModelClassMethodCall ( ) {
68
- model = modelApiNode ( ) and
69
- this = classMethodCall ( model , _)
70
- }
103
+ ModelClassMethodCall ( ) { this = cls .trackModule ( ) .getAMethodCall ( _) }
71
104
72
105
/** Gets the model class for this call. */
73
- ModelClass getModelClass ( ) { result . getModelApiNode ( ) = model }
106
+ ModelClassNode getModelClass ( ) { result = cls }
74
107
}
75
108
76
109
/**
77
110
* A call to `site=` on an ActiveResource model class.
78
111
* This sets the base URL for all HTTP requests made by this class.
79
112
*/
80
- private class SiteAssignCall extends DataFlow:: CallNode {
81
- API:: Node model ;
82
-
83
- SiteAssignCall ( ) { model = modelApiNode ( ) and this = classMethodCall ( model , "site=" ) }
113
+ private class SiteAssignCall extends ModelClassMethodCall {
114
+ SiteAssignCall ( ) { this .getMethodName ( ) = "site=" }
84
115
85
116
/**
86
117
* Gets a node that contributes to the URLs used for HTTP requests by the parent
87
118
* class.
88
119
*/
89
120
DataFlow:: Node getAUrlPart ( ) { result = this .getArgument ( 0 ) }
90
121
91
- /** Gets the model class for this call. */
92
- ModelClass getModelClass ( ) { result .getModelApiNode ( ) = model }
93
-
94
122
/** Holds if this site value specifies HTTP rather than HTTPS. */
95
123
predicate disablesCertificateValidation ( ) {
96
124
this .getAUrlPart ( )
125
+ // TODO: We should not need all this just to get the string value
97
126
.asExpr ( )
98
127
.( ExprNodes:: AssignExprCfgNode )
99
128
.getRhs ( )
@@ -141,87 +170,70 @@ module ActiveResource {
141
170
}
142
171
143
172
/**
173
+ * DEPRECATED. Use `ModelClassNode.getAnInstanceReference()` instead.
174
+ *
144
175
* An ActiveResource model object.
145
176
*/
146
- class ModelInstance extends DataFlow:: Node {
147
- ModelClass cls ;
148
-
149
- ModelInstance ( ) {
150
- exists ( API:: Node model | model = modelApiNode ( ) |
151
- this = model .getInstance ( ) .getAValueReachableFromSource ( ) and
152
- cls .getModelApiNode ( ) = model
153
- )
154
- or
155
- exists ( FindCall call | call .flowsTo ( this ) | cls = call .getModelClass ( ) )
156
- or
157
- exists ( CreateCall call | call .flowsTo ( this ) | cls = call .getModelClass ( ) )
158
- or
159
- exists ( CustomHttpCall call | call .flowsTo ( this ) | cls = call .getModelClass ( ) )
160
- or
161
- exists ( CollectionCall call |
162
- call .getMethodName ( ) = [ "first" , "last" ] and
163
- call .flowsTo ( this )
164
- |
165
- cls = call .getCollection ( ) .getModelClass ( )
166
- )
167
- }
177
+ deprecated class ModelInstance extends DataFlow:: Node {
178
+ private ModelClassNode cls ;
179
+
180
+ ModelInstance ( ) { this = cls .getAnInstanceReference ( ) .getAValueReachableFromSource ( ) }
168
181
169
182
/** Gets the model class for this instance. */
170
- ModelClass getModelClass ( ) { result = cls }
183
+ ModelClassNode getModelClass ( ) { result = cls }
171
184
}
172
185
173
186
/**
174
187
* A call to a method on an ActiveResource model object.
175
188
*/
176
189
class ModelInstanceMethodCall extends DataFlow:: CallNode {
177
- ModelInstance i ;
190
+ private ModelClassNode cls ;
178
191
179
- ModelInstanceMethodCall ( ) { this . getReceiver ( ) = i }
192
+ ModelInstanceMethodCall ( ) { this = cls . getAnInstanceReference ( ) . getAMethodCall ( _ ) }
180
193
181
194
/** Gets the model instance for this call. */
182
- ModelInstance getInstance ( ) { result = i }
195
+ deprecated ModelInstance getInstance ( ) { result = this . getReceiver ( ) }
183
196
184
197
/** Gets the model class for this call. */
185
- ModelClass getModelClass ( ) { result = i . getModelClass ( ) }
198
+ ModelClassNode getModelClass ( ) { result = cls }
186
199
}
187
200
188
201
/**
189
- * A collection of ActiveResource model objects.
202
+ * DEPRECATED. Use `CollectionSource` instead.
203
+ *
204
+ * A data flow node that may refer to a collection of ActiveResource model objects.
190
205
*/
191
- class Collection extends DataFlow:: Node {
192
- ModelClassMethodCall classMethodCall ;
193
-
194
- Collection ( ) {
195
- classMethodCall .flowsTo ( this ) and
196
- (
197
- classMethodCall .getMethodName ( ) = "all"
198
- or
199
- classMethodCall .getMethodName ( ) = "find" and
200
- classMethodCall .getArgument ( 0 ) .asExpr ( ) .getConstantValue ( ) .isStringlikeValue ( "all" )
201
- )
202
- }
206
+ deprecated class Collection extends DataFlow:: Node {
207
+ Collection ( ) { this = any ( CollectionSource src ) .track ( ) .getAValueReachableFromSource ( ) }
208
+ }
203
209
204
- /** Gets the model class for this collection. */
205
- ModelClass getModelClass ( ) { result = classMethodCall .getModelClass ( ) }
210
+ /**
211
+ * A call that returns a collection of ActiveResource model objects.
212
+ */
213
+ class CollectionSource extends ModelClassMethodCall {
214
+ CollectionSource ( ) {
215
+ this .getMethodName ( ) = "all"
216
+ or
217
+ this .getArgument ( 0 ) .asExpr ( ) .getConstantValue ( ) .isStringlikeValue ( "all" )
218
+ }
206
219
}
207
220
208
221
/**
209
222
* A method call on a collection.
210
223
*/
211
224
class CollectionCall extends DataFlow:: CallNode {
212
- CollectionCall ( ) { this .getReceiver ( ) instanceof Collection }
225
+ private CollectionSource collection ;
226
+
227
+ CollectionCall ( ) { this = collection .track ( ) .getAMethodCall ( _) }
213
228
214
229
/** Gets the collection for this call. */
215
- Collection getCollection ( ) { result = this . getReceiver ( ) }
230
+ CollectionSource getCollection ( ) { result = collection }
216
231
}
217
232
218
233
private class ModelClassMethodCallAsHttpRequest extends Http:: Client:: Request:: Range ,
219
234
ModelClassMethodCall
220
235
{
221
- ModelClass cls ;
222
-
223
236
ModelClassMethodCallAsHttpRequest ( ) {
224
- this .getModelClass ( ) = cls and
225
237
this .getMethodName ( ) = [ "all" , "build" , "create" , "create!" , "find" , "first" , "last" ]
226
238
}
227
239
@@ -230,23 +242,22 @@ module ActiveResource {
230
242
override predicate disablesCertificateValidation (
231
243
DataFlow:: Node disablingNode , DataFlow:: Node argumentOrigin
232
244
) {
233
- cls .disablesCertificateValidation ( disablingNode ) and
245
+ this . getModelClass ( ) .disablesCertificateValidation ( disablingNode ) and
234
246
// TODO: highlight real argument origin
235
247
argumentOrigin = disablingNode
236
248
}
237
249
238
- override DataFlow:: Node getAUrlPart ( ) { result = cls .getASiteAssignment ( ) .getAUrlPart ( ) }
250
+ override DataFlow:: Node getAUrlPart ( ) {
251
+ result = this .getModelClass ( ) .getASiteAssignment ( ) .getAUrlPart ( )
252
+ }
239
253
240
254
override DataFlow:: Node getResponseBody ( ) { result = this }
241
255
}
242
256
243
257
private class ModelInstanceMethodCallAsHttpRequest extends Http:: Client:: Request:: Range ,
244
258
ModelInstanceMethodCall
245
259
{
246
- ModelClass cls ;
247
-
248
260
ModelInstanceMethodCallAsHttpRequest ( ) {
249
- this .getModelClass ( ) = cls and
250
261
this .getMethodName ( ) =
251
262
[
252
263
"exists?" , "reload" , "save" , "save!" , "destroy" , "delete" , "get" , "patch" , "post" , "put" ,
@@ -259,42 +270,15 @@ module ActiveResource {
259
270
override predicate disablesCertificateValidation (
260
271
DataFlow:: Node disablingNode , DataFlow:: Node argumentOrigin
261
272
) {
262
- cls .disablesCertificateValidation ( disablingNode ) and
273
+ this . getModelClass ( ) .disablesCertificateValidation ( disablingNode ) and
263
274
// TODO: highlight real argument origin
264
275
argumentOrigin = disablingNode
265
276
}
266
277
267
- override DataFlow:: Node getAUrlPart ( ) { result = cls .getASiteAssignment ( ) .getAUrlPart ( ) }
278
+ override DataFlow:: Node getAUrlPart ( ) {
279
+ result = this .getModelClass ( ) .getASiteAssignment ( ) .getAUrlPart ( )
280
+ }
268
281
269
282
override DataFlow:: Node getResponseBody ( ) { result = this }
270
283
}
271
-
272
- /**
273
- * A call to a class method.
274
- *
275
- * TODO: is this general enough to be useful elsewhere?
276
- *
277
- * Examples:
278
- * ```rb
279
- * class A
280
- * def self.m; end
281
- *
282
- * m # call
283
- * end
284
- *
285
- * A.m # call
286
- * ```
287
- */
288
- private DataFlow:: CallNode classMethodCall ( API:: Node classNode , string methodName ) {
289
- // A.m
290
- result = classNode .getAMethodCall ( methodName )
291
- or
292
- // class A
293
- // A.m
294
- // end
295
- result .getReceiver ( ) .asExpr ( ) instanceof ExprNodes:: SelfVariableAccessCfgNode and
296
- result .asExpr ( ) .getExpr ( ) .getEnclosingModule ( ) .( ClassDeclaration ) .getSuperclassExpr ( ) =
297
- classNode .getAValueReachableFromSource ( ) .asExpr ( ) .getExpr ( ) and
298
- result .getMethodName ( ) = methodName
299
- }
300
284
}
0 commit comments