@@ -852,6 +852,26 @@ module PrivateDjango {
852852 )
853853 }
854854
855+ /**
856+ * Gets the synthetic node where data could be loaded from, when a fetch is
857+ * made on `modelClass`.
858+ *
859+ * In vanilla Django inheritance, this is simply the model itself, but if a
860+ * model is based on `polymorphic.models.PolymorphicModel`, a fetch of the
861+ * base-class can also yield instances of its subclasses.
862+ */
863+ SyntheticDjangoOrmModelNode nodeToLoadFrom ( API:: Node modelClass ) {
864+ result .getModelClass ( ) = modelClass
865+ or
866+ exists ( API:: Node polymorphicModel |
867+ polymorphicModel =
868+ API:: moduleImport ( "polymorphic" ) .getMember ( "models" ) .getMember ( "PolymorphicModel" )
869+ |
870+ polymorphicModel .getASubclass + ( ) = modelClass and
871+ modelClass .getASubclass + ( ) = result .getModelClass ( )
872+ )
873+ }
874+
855875 /** Additional data-flow steps for Django ORM models. */
856876 class DjangOrmSteps extends AdditionalOrmSteps {
857877 override predicate storeStep (
@@ -908,15 +928,15 @@ module PrivateDjango {
908928 or
909929 // synthetic -> method-call that returns collection of ORM models (all/filter/...)
910930 exists ( API:: Node modelClass |
911- nodeFrom . ( SyntheticDjangoOrmModelNode ) . getModelClass ( ) = modelClass and
931+ nodeFrom = nodeToLoadFrom ( modelClass ) and
912932 nodeTo .( Model:: QuerySetMethodInstanceCollection ) .getModelClass ( ) = modelClass and
913933 nodeTo .( Model:: QuerySetMethodInstanceCollection ) .isDbFetch ( ) and
914934 c instanceof DataFlow:: ListElementContent
915935 )
916936 or
917937 // synthetic -> method-call that returns dictionary with ORM models as values
918938 exists ( API:: Node modelClass |
919- nodeFrom . ( SyntheticDjangoOrmModelNode ) . getModelClass ( ) = modelClass and
939+ nodeFrom = nodeToLoadFrom ( modelClass ) and
920940 nodeTo .( Model:: QuerySetMethodInstanceDictValue ) .getModelClass ( ) = modelClass and
921941 nodeTo .( Model:: QuerySetMethodInstanceDictValue ) .isDbFetch ( ) and
922942 c instanceof DataFlow:: DictionaryElementAnyContent
@@ -938,9 +958,9 @@ module PrivateDjango {
938958 or
939959 // synthetic -> method-call that returns single ORM model (get/first/...)
940960 exists ( API:: Node modelClass |
961+ nodeFrom = nodeToLoadFrom ( modelClass ) and
941962 nodeTo .( Model:: InstanceSource ) .getModelClass ( ) = modelClass and
942- nodeTo .( Model:: InstanceSource ) .isDbFetch ( ) and
943- nodeFrom .( SyntheticDjangoOrmModelNode ) .getModelClass ( ) = modelClass
963+ nodeTo .( Model:: InstanceSource ) .isDbFetch ( )
944964 )
945965 }
946966 }
0 commit comments