Skip to content

Commit 9721e3e

Browse files
committed
Improve QLDoc and change note
1 parent 5b8e1bc commit 9721e3e

2 files changed

Lines changed: 10 additions & 8 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
---
22
category: minorAnalysis
33
---
4-
* Type tracking now works for values stored in instance attributes and read from outside the class (for example `instance.attr` where the value was assigned to `self.attr` in a method). For performance reasons it may not identify all instances that flow across a call or return before being read.
4+
* Type tracking now works for values stored in instance attributes and read from outside the class (for example `instance.attr` where the value was assigned to `self.attr` in a method), provided the instance at the read is reachable by local flow from a resolved constructor call. This excludes, for example, instances returned by a function and module-level instances read inside a function.

‎python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,15 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
353353
* call `cls(...)` (resolved via the call graph by `resolveClassCall`), rather than a
354354
* dedicated instance type-tracker (`classInstanceTracker`).
355355
*
356-
* Using `classInstanceTracker` here would make `levelStepCall` mutually recursive with
357-
* `classInstanceTracker` -- itself a full type-tracker run -- which caused catastrophic
358-
* query slowdowns on some OOP-heavy Python code bases (e.g. `mypy` and `dask`). Relying
359-
* on local flow from a resolved constructor call instead depends only on `classTracker`
360-
* (the same call-graph machinery already used by `inheritedFieldStep`), avoiding that
361-
* blow-up. The trade-off is reduced precision: instances that flow across a call or
362-
* return before being read are no longer covered by this step.
356+
* This removes the direct use of `classInstanceTracker` here, which previously caused
357+
* catastrophic query slowdowns on some OOP-heavy Python code bases (e.g. `mypy` and
358+
* `dask`). Indirect recursion remains: `resolveClassCall` uses `classTracker` and
359+
* `clsArgumentTracker`, and `classTracker` can depend on `classInstanceTracker` through
360+
* `type(obj)`. The performance impact on those code bases still needs validation.
361+
*
362+
* Only instances reachable by local flow from a resolved constructor call are covered
363+
* by this step. This excludes, for example, instances returned by a function and
364+
* module-level instances read inside a function.
363365
*/
364366
private predicate instanceAttrRead(Class cls, string attr, DataFlowPublic::AttrRead read) {
365367
exists(DataFlowPublic::CallCfgNode construction |

0 commit comments

Comments
 (0)