Python: Port Django view modeling to API graphs

This commit is contained in:
Rasmus Wriedt Larsen
2021-03-27 18:58:37 +01:00
parent 8ce5c46e05
commit 322bdcb703

View File

@@ -1519,402 +1519,54 @@ private module Django {
/** Provides models for the `django.views` module */
module views {
/**
* Gets a reference to the attribute `attr_name` of the `django.views` module.
* WARNING: Only holds for a few predefined attributes.
* Provides models for the `django.views.generic.View` class and subclasses.
*
* See
* - https://docs.djangoproject.com/en/3.1/topics/class-based-views/
* - https://docs.djangoproject.com/en/3.1/ref/class-based-views/
*/
private DataFlow::Node views_attr(DataFlow::TypeTracker t, string attr_name) {
// for 1.11.x, see: https://github.com/django/django/blob/stable/1.11.x/django/views/__init__.py
attr_name in ["generic", "View"] and
(
t.start() and
result = DataFlow::importNode("django.views" + "." + attr_name)
or
t.startInAttr(attr_name) and
result = views()
)
or
// Due to bad performance when using normal setup with `views_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
views_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate views_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(views_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node views_attr(string attr_name) {
result = views_attr(DataFlow::TypeTracker::end(), attr_name)
}
// -------------------------------------------------------------------------
// django.views.generic
// -------------------------------------------------------------------------
/** Gets a reference to the `django.views.generic` module. */
DataFlow::Node generic() { result = views_attr("generic") }
/** Provides models for the `django.views.generic` module */
module generic {
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node generic_attr(DataFlow::TypeTracker t, string attr_name) {
// for 3.1.x see: https://github.com/django/django/blob/stable/3.1.x/django/views/generic/__init__.py
// same for 1.11.x see: https://github.com/django/django/blob/stable/1.11.x/django/views/generic/__init__.py
attr_name in [
"View", "TemplateView", "RedirectView", "ArchiveIndexView", "YearArchiveView",
"MonthArchiveView", "WeekArchiveView", "DayArchiveView", "TodayArchiveView",
"DateDetailView", "DetailView", "FormView", "CreateView", "UpdateView", "DeleteView",
"ListView", "GenericViewError",
// modules
"base", "dates", "detail", "edit", "list"
] and
(
t.start() and
result = DataFlow::importNode("django.views.generic" + "." + attr_name)
module View {
/** Gets a reference to the `django.views.generic.View` class or any subclass. */
API::Node subclassRef() {
exists(string moduleName, string className |
// canonical definition
result =
API::moduleImport("django")
.getMember("views")
.getMember("generic")
.getMember(moduleName)
.getMember(className)
.getASubclass*()
or
t.startInAttr(attr_name) and
result = generic()
)
or
// Due to bad performance when using normal setup with `generic_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
generic_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate generic_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(generic_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node generic_attr(string attr_name) {
result = generic_attr(DataFlow::TypeTracker::end(), attr_name)
}
// -------------------------------------------------------------------------
// django.views.generic.base
// -------------------------------------------------------------------------
/** Gets a reference to the `django.views.generic.base` module. */
DataFlow::Node base() { result = generic_attr("base") }
/** Provides models for the `django.views.generic.base` module */
module base {
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.base` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node base_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["RedirectView", "TemplateView", "View"] and
(
t.start() and
result = DataFlow::importNode("django.views.generic.base" + "." + attr_name)
or
t.startInAttr(attr_name) and
result = base()
)
// alias from `django.view.generic`
result =
API::moduleImport("django")
.getMember("view")
.getMember("generic")
.getMember(className)
.getASubclass*()
|
moduleName = "base" and
className in ["RedirectView", "TemplateView", "View"]
or
// Due to bad performance when using normal setup with `base_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
base_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate base_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(base_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.base` module.
* WARNING: Only holds for a few predefined attributes.
*/
DataFlow::Node base_attr(string attr_name) {
result = base_attr(DataFlow::TypeTracker::end(), attr_name)
}
}
// -------------------------------------------------------------------------
// django.views.generic.dates
// -------------------------------------------------------------------------
/** Gets a reference to the `django.views.generic.dates` module. */
DataFlow::Node dates() { result = generic_attr("dates") }
/** Provides models for the `django.views.generic.dates` module */
module dates {
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.dates` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node dates_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in [
moduleName = "dates" and
className in [
"ArchiveIndexView", "DateDetailView", "DayArchiveView", "MonthArchiveView",
"TodayArchiveView", "WeekArchiveView", "YearArchiveView"
] and
(
t.start() and
result = DataFlow::importNode("django.views.generic.dates" + "." + attr_name)
or
t.startInAttr(attr_name) and
result = dates()
)
]
or
// Due to bad performance when using normal setup with `dates_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
dates_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate dates_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(dates_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.dates` module.
* WARNING: Only holds for a few predefined attributes.
*/
DataFlow::Node dates_attr(string attr_name) {
result = dates_attr(DataFlow::TypeTracker::end(), attr_name)
}
}
// -------------------------------------------------------------------------
// django.views.generic.detail
// -------------------------------------------------------------------------
/** Gets a reference to the `django.views.generic.detail` module. */
DataFlow::Node detail() { result = generic_attr("detail") }
/** Provides models for the `django.views.generic.detail` module */
module detail {
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.detail` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node detail_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["DetailView"] and
(
t.start() and
result = DataFlow::importNode("django.views.generic.detail" + "." + attr_name)
or
t.startInAttr(attr_name) and
result = detail()
)
moduleName = "detail" and
className = "DetailView"
or
// Due to bad performance when using normal setup with `detail_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
detail_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate detail_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(detail_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.detail` module.
* WARNING: Only holds for a few predefined attributes.
*/
DataFlow::Node detail_attr(string attr_name) {
result = detail_attr(DataFlow::TypeTracker::end(), attr_name)
}
}
// -------------------------------------------------------------------------
// django.views.generic.edit
// -------------------------------------------------------------------------
/** Gets a reference to the `django.views.generic.edit` module. */
DataFlow::Node edit() { result = generic_attr("edit") }
/** Provides models for the `django.views.generic.edit` module */
module edit {
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.edit` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node edit_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["CreateView", "DeleteView", "FormView", "UpdateView"] and
(
t.start() and
result = DataFlow::importNode("django.views.generic.edit" + "." + attr_name)
or
t.startInAttr(attr_name) and
result = edit()
)
moduleName = "edit" and
className in ["CreateView", "DeleteView", "FormView", "UpdateView"]
or
// Due to bad performance when using normal setup with `edit_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
edit_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate edit_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(edit_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.edit` module.
* WARNING: Only holds for a few predefined attributes.
*/
DataFlow::Node edit_attr(string attr_name) {
result = edit_attr(DataFlow::TypeTracker::end(), attr_name)
}
}
// -------------------------------------------------------------------------
// django.views.generic.list
// -------------------------------------------------------------------------
/** Gets a reference to the `django.views.generic.list` module. */
DataFlow::Node list() { result = generic_attr("list") }
/** Provides models for the `django.views.generic.list` module */
module list {
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.list` module.
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node list_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["ListView"] and
(
t.start() and
result = DataFlow::importNode("django.views.generic.list" + "." + attr_name)
or
t.startInAttr(attr_name) and
result = list()
)
or
// Due to bad performance when using normal setup with `list_attr(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
list_attr_first_join(t2, attr_name, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate list_attr_first_join(
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(list_attr(t2, attr_name), res, summary)
}
/**
* Gets a reference to the attribute `attr_name` of the `django.views.generic.list` module.
* WARNING: Only holds for a few predefined attributes.
*/
DataFlow::Node list_attr(string attr_name) {
result = list_attr(DataFlow::TypeTracker::end(), attr_name)
}
}
/**
* Provides models for the `django.views.generic.View` class and subclasses.
*
* See
* - https://docs.djangoproject.com/en/3.1/topics/class-based-views/
* - https://docs.djangoproject.com/en/3.1/ref/class-based-views/
*/
module View {
/** Gets a reference to the `django.views.generic.View` class or any subclass. */
private DataFlow::Node subclassRef(DataFlow::TypeTracker t) {
t.start() and
result =
generic_attr([
"View",
// Known Views
"TemplateView", "RedirectView", "ArchiveIndexView", "YearArchiveView",
"MonthArchiveView", "WeekArchiveView", "DayArchiveView", "TodayArchiveView",
"DateDetailView", "DetailView", "FormView", "CreateView", "UpdateView",
"DeleteView", "ListView"
])
or
// aliases
t.start() and
(
// django.views.View
result = views_attr("View")
or
// django.views.generic.base.*
result = base::base_attr(_)
or
// django.views.generic.dates.*
result = dates::dates_attr(_)
or
// django.views.generic.detail.*
result = detail::detail_attr(_)
or
// django.views.generic.edit.*
result = edit::edit_attr(_)
or
// django.views.generic.list.*
result = list::list_attr(_)
)
or
// subclasses in project code
result.asExpr().(ClassExpr).getABase() = subclassRef(t.continue()).asExpr()
or
exists(DataFlow::TypeTracker t2 | result = subclassRef(t2).track(t2, t))
}
/** Gets a reference to the `django.views.generic.View` class or any subclass. */
DataFlow::Node subclassRef() { result = subclassRef(DataFlow::TypeTracker::end()) }
moduleName = "list" and
className = "ListView"
)
or
// `django.views.View` alias
result = API::moduleImport("django").getMember("views").getMember("View").getASubclass*()
}
}
}
@@ -2389,7 +2041,7 @@ private module Django {
*/
class DjangoViewClassFromSuperClass extends DjangoViewClass {
DjangoViewClassFromSuperClass() {
this.getABase() = django::views::generic::View::subclassRef().asExpr()
this.getABase() = django::views::View::subclassRef().getAUse().asExpr()
}
}