@@ -90,6 +90,136 @@ private module Django {
9090
9191 /** Gets a reference to the `django.db.connection.cursor.execute` function. */
9292 DataFlow:: Node execute ( ) { result = execute ( DataFlow:: TypeTracker:: end ( ) ) }
93+
94+ /** Gets a reference to the `django.db.models` module. */
95+ private DataFlow:: Node models ( DataFlow:: TypeTracker t ) {
96+ t .start ( ) and
97+ result = DataFlow:: importNode ( "django.db.models" )
98+ or
99+ t .startInAttr ( "models" ) and
100+ result = django ( )
101+ or
102+ exists ( DataFlow:: TypeTracker t2 | result = models ( t2 ) .track ( t2 , t ) )
103+ }
104+
105+ /** Gets a reference to the `django.db.models` module. */
106+ DataFlow:: Node models ( ) { result = models ( DataFlow:: TypeTracker:: end ( ) ) }
107+
108+ /** Provides models for the `django.db.models` module. */
109+ module models {
110+ /** Gets a reference to the `django.db.models.Model` class. */
111+ private DataFlow:: Node classModel ( DataFlow:: TypeTracker t ) {
112+ t .start ( ) and
113+ result = DataFlow:: importNode ( "django.db.models.Model" )
114+ or
115+ t .startInAttr ( "Model" ) and
116+ result = models ( )
117+ or
118+ exists ( DataFlow:: TypeTracker t2 | result = classModel ( t2 ) .track ( t2 , t ) )
119+ }
120+
121+ /** Gets a reference to the `django.db.models.Model` class. */
122+ DataFlow:: Node classModel ( ) { result = classModel ( DataFlow:: TypeTracker:: end ( ) ) }
123+
124+ /** Gets a definition of a subclass the `django.db.models.Model` class. */
125+ class ClassModelSubclassDef extends ControlFlowNode {
126+ string name ;
127+
128+ ClassModelSubclassDef ( ) {
129+ exists ( ClassExpr ce |
130+ this .getNode ( ) = ce and
131+ ce .getABase ( ) = classModel ( ) .asExpr ( ) and
132+ ce .getName ( ) = name
133+ )
134+ }
135+
136+ string getName ( ) { result = name }
137+ }
138+
139+ /**
140+ * A reference to a class that is a subclass of the `django.db.models.Model` class.
141+ * This is quite an approximation, since it simply matches identifiers.
142+ */
143+ class ClassModelSubclass extends DataFlow:: CfgNode {
144+ override NameNode node ;
145+
146+ ClassModelSubclass ( ) { node .getId ( ) = any ( ClassModelSubclassDef cd ) .getName ( ) }
147+ }
148+
149+ /** Gets a reference to the `objects` object of a model. */
150+ private DataFlow:: Node objects ( DataFlow:: TypeTracker t ) {
151+ t .startInAttr ( "objects" ) and
152+ result instanceof ClassModelSubclass
153+ or
154+ exists ( DataFlow:: TypeTracker t2 | result = objects ( t2 ) .track ( t2 , t ) )
155+ }
156+
157+ /** Gets a reference to the `objects` object of a model. */
158+ DataFlow:: Node objects ( ) { result = objects ( DataFlow:: TypeTracker:: end ( ) ) }
159+
160+ /**
161+ * Gets a reference to the attribute `attr_name` of an `objects` object.
162+ * WARNING: Only holds for a few predefined attributes.
163+ */
164+ private DataFlow:: Node objects_attr ( DataFlow:: TypeTracker t , string attr_name ) {
165+ attr_name in [ "annotate" , "extra" , "raw" ] and
166+ t .startInAttr ( attr_name ) and
167+ result = objects ( )
168+ or
169+ // Due to bad performance when using normal setup with `objects_attr(t2, attr_name).track(t2, t)`
170+ // we have inlined that code and forced a join
171+ exists ( DataFlow:: TypeTracker t2 |
172+ exists ( DataFlow:: StepSummary summary |
173+ objects_attr_first_join ( t2 , attr_name , result , summary ) and
174+ t = t2 .append ( summary )
175+ )
176+ )
177+ }
178+
179+ pragma [ nomagic]
180+ private predicate objects_attr_first_join (
181+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res ,
182+ DataFlow:: StepSummary summary
183+ ) {
184+ DataFlow:: StepSummary:: step ( objects_attr ( t2 , attr_name ) , res , summary )
185+ }
186+
187+ /**
188+ * Gets a reference to the attribute `attr_name` of an `objects` object.
189+ * WARNING: Only holds for a few predefined attributes.
190+ */
191+ DataFlow:: Node objects_attr ( string attr_name ) {
192+ result = objects_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
193+ }
194+
195+ /** Gets a reference to the `django.db.models.expressions` object. */
196+ private DataFlow:: Node expressions ( DataFlow:: TypeTracker t ) {
197+ t .start ( ) and
198+ result = DataFlow:: importNode ( "django.db.models.expressions" )
199+ or
200+ t .startInAttr ( "expressions" ) and
201+ result = models ( )
202+ or
203+ exists ( DataFlow:: TypeTracker t2 | result = expressions ( t2 ) .track ( t2 , t ) )
204+ }
205+
206+ /** Gets a reference to the `django.db.models.expressions` object. */
207+ DataFlow:: Node expressions ( ) { result = expressions ( DataFlow:: TypeTracker:: end ( ) ) }
208+
209+ /** Gets a reference to the `django.db.models.expressions.RawSQL` class. */
210+ private DataFlow:: Node classRawSQL ( DataFlow:: TypeTracker t ) {
211+ t .start ( ) and
212+ result = DataFlow:: importNode ( "django.db.models.expressions.RawSQL" )
213+ or
214+ t .startInAttr ( "RawSQL" ) and
215+ result = expressions ( )
216+ or
217+ exists ( DataFlow:: TypeTracker t2 | result = classRawSQL ( t2 ) .track ( t2 , t ) )
218+ }
219+
220+ /** Gets a reference to the `django.db.models.expressions.RawSQL` class. */
221+ DataFlow:: Node classRawSQL ( ) { result = classRawSQL ( DataFlow:: TypeTracker:: end ( ) ) }
222+ }
93223 }
94224 }
95225
@@ -101,4 +231,36 @@ private module Django {
101231
102232 override DataFlow:: Node getSql ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
103233 }
234+
235+ /** A call to the `annotate` function on a model using a `RawSQL` argument. */
236+ private class ObjectsAnnotate extends SqlExecution:: Range , DataFlow:: CfgNode {
237+ override CallNode node ;
238+ CallNode raw ;
239+
240+ ObjectsAnnotate ( ) {
241+ node .getFunction ( ) = django:: db:: models:: objects_attr ( "annotate" ) .asCfgNode ( ) and
242+ raw = node .getArg ( 0 ) and
243+ raw .getFunction ( ) = django:: db:: models:: classRawSQL ( ) .asCfgNode ( )
244+ }
245+
246+ override DataFlow:: Node getSql ( ) { result .asCfgNode ( ) = raw .getArg ( 0 ) }
247+ }
248+
249+ /** A call to the `raw` function on a model. */
250+ private class ObjectsRaw extends SqlExecution:: Range , DataFlow:: CfgNode {
251+ override CallNode node ;
252+
253+ ObjectsRaw ( ) { node .getFunction ( ) = django:: db:: models:: objects_attr ( "raw" ) .asCfgNode ( ) }
254+
255+ override DataFlow:: Node getSql ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
256+ }
257+
258+ /** A call to the `raw` function on a model. */
259+ private class ObjectsExtra extends SqlExecution:: Range , DataFlow:: CfgNode {
260+ override CallNode node ;
261+
262+ ObjectsExtra ( ) { node .getFunction ( ) = django:: db:: models:: objects_attr ( "extra" ) .asCfgNode ( ) }
263+
264+ override DataFlow:: Node getSql ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
265+ }
104266}
0 commit comments