From 78c33ab55a2c9fbb8a26c0cf313d878fc64a2eb5 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 16:37:28 +0000 Subject: [PATCH 01/22] Python: Remove points-to references from `python.qll` For now, these have just been made into `private` imports. After doing this, I went through all of the (now not compiling) files and added in private imports to the modules that they actually depended on. I also added an explicit import of `LegacyPointsTo` (even though it may be unnecessary) in cases where the points-to dependency was somewhat surprising (and one we want to get rid of). This was primarily inside the various SSA layers. For modules inside `semmle.python.{types, objects, pointsto}` I did not bother, as these are fairly clearly related to points-to. --- python/ql/lib/LegacyPointsTo.qll | 17 ++++++++++-- python/ql/lib/analysis/DefinitionTracking.qll | 1 - python/ql/lib/python.qll | 26 +++++++++---------- python/ql/lib/semmle/python/Flow.qll | 1 + python/ql/lib/semmle/python/SSA.qll | 1 + python/ql/lib/semmle/python/SelfAttribute.qll | 1 + .../new/internal/ImportResolution.qll | 1 + .../python/dataflow/old/Configuration.qll | 2 +- .../lib/semmle/python/dataflow/old/Files.qll | 1 + .../python/dataflow/old/Implementation.qll | 1 - .../python/dataflow/old/StateTracking.qll | 4 +-- .../python/dataflow/old/TaintTracking.qll | 1 - .../python/dependencies/DependencyKind.qll | 1 + .../python/dependencies/TechInventory.qll | 1 + .../ql/lib/semmle/python/essa/Definitions.qll | 4 ++- python/ql/lib/semmle/python/essa/Essa.qll | 2 ++ .../lib/semmle/python/essa/SsaDefinitions.qll | 1 + .../ql/lib/semmle/python/libraries/Zope.qll | 2 +- .../lib/semmle/python/objects/Constants.qll | 1 + .../lib/semmle/python/objects/Descriptors.qll | 1 + .../lib/semmle/python/objects/Instances.qll | 2 ++ .../ql/lib/semmle/python/objects/Modules.qll | 1 + .../lib/semmle/python/objects/ObjectAPI.qll | 3 --- .../ql/lib/semmle/python/objects/TObject.qll | 1 + python/ql/lib/semmle/python/pointsto/Base.qll | 2 ++ .../lib/semmle/python/pointsto/CallGraph.qll | 2 ++ .../lib/semmle/python/pointsto/PointsTo.qll | 5 ++++ .../python/pointsto/PointsToContext.qll | 2 ++ .../ql/lib/semmle/python/types/Builtins.qll | 1 + .../lib/semmle/python/types/ClassObject.qll | 1 + .../lib/semmle/python/types/Descriptors.qll | 3 +++ .../ql/lib/semmle/python/types/Extensions.qll | 1 + .../semmle/python/types/FunctionObject.qll | 3 --- .../ql/lib/semmle/python/types/ModuleKind.qll | 1 + .../lib/semmle/python/types/ModuleObject.qll | 3 +++ python/ql/lib/semmle/python/types/Object.qll | 1 - .../semmle/python/values/StringAttributes.qll | 3 --- .../src/Expressions/ContainsNonContainer.ql | 1 - python/ql/src/Expressions/IsComparisons.qll | 1 + .../ql/src/Statements/RedundantAssignment.ql | 1 + python/ql/src/Variables/UndefinedGlobal.ql | 1 - python/ql/src/Variables/UninitializedLocal.ql | 1 - python/ql/src/analysis/Efficiency.ql | 2 -- 43 files changed, 73 insertions(+), 39 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index 3e675854601..bc2a6b7804a 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -20,8 +20,21 @@ */ private import python -private import semmle.python.pointsto.PointsTo -private import semmle.python.objects.Modules +import semmle.python.pointsto.Base +import semmle.python.pointsto.Context +import semmle.python.pointsto.PointsTo +import semmle.python.pointsto.PointsToContext +import semmle.python.objects.ObjectAPI +import semmle.python.objects.ObjectInternal +import semmle.python.types.Object +import semmle.python.types.ClassObject +import semmle.python.types.FunctionObject +import semmle.python.types.ModuleObject +import semmle.python.types.Exceptions +import semmle.python.types.Properties +import semmle.python.types.ImportTime +import semmle.python.types.Descriptors +import semmle.python.SelfAttribute /** * An extension of `ControlFlowNode` that provides points-to predicates. diff --git a/python/ql/lib/analysis/DefinitionTracking.qll b/python/ql/lib/analysis/DefinitionTracking.qll index 53f8e791cd8..c019e92c0ca 100644 --- a/python/ql/lib/analysis/DefinitionTracking.qll +++ b/python/ql/lib/analysis/DefinitionTracking.qll @@ -4,7 +4,6 @@ import python private import LegacyPointsTo -import semmle.python.pointsto.PointsTo import IDEContextual private newtype TDefinition = diff --git a/python/ql/lib/python.qll b/python/ql/lib/python.qll index b08f0ae35bb..d127e297dbb 100644 --- a/python/ql/lib/python.qll +++ b/python/ql/lib/python.qll @@ -19,22 +19,22 @@ import semmle.python.Constants import semmle.python.Scope import semmle.python.Comment import semmle.python.GuardedControlFlow -import semmle.python.types.ImportTime -import semmle.python.types.Object -import semmle.python.types.ClassObject -import semmle.python.types.FunctionObject -import semmle.python.types.ModuleObject -import semmle.python.types.Version -import semmle.python.types.Descriptors +private import semmle.python.types.ImportTime +private import semmle.python.types.Object +private import semmle.python.types.ClassObject +private import semmle.python.types.FunctionObject +private import semmle.python.types.ModuleObject +private import semmle.python.types.Version +private import semmle.python.types.Descriptors import semmle.python.SSA -import semmle.python.SelfAttribute -import semmle.python.types.Properties +private import semmle.python.SelfAttribute +private import semmle.python.types.Properties import semmle.python.xml.XML import semmle.python.essa.Essa -import semmle.python.pointsto.Base -import semmle.python.pointsto.Context -import semmle.python.pointsto.CallGraph -import semmle.python.objects.ObjectAPI +private import semmle.python.pointsto.Base +private import semmle.python.pointsto.Context +private import semmle.python.pointsto.CallGraph +private import semmle.python.objects.ObjectAPI import semmle.python.Unit import site private import semmle.python.Overlay diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 496c1abc52a..6574979f9c8 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -1,6 +1,7 @@ import python private import semmle.python.internal.CachedStages private import codeql.controlflow.BasicBlock as BB +private import LegacyPointsTo /* * Note about matching parent and child nodes and CFG splitting: diff --git a/python/ql/lib/semmle/python/SSA.qll b/python/ql/lib/semmle/python/SSA.qll index 98cd39a4c43..a139f22dfc6 100644 --- a/python/ql/lib/semmle/python/SSA.qll +++ b/python/ql/lib/semmle/python/SSA.qll @@ -1,6 +1,7 @@ /** SSA library */ import python +private import LegacyPointsTo /** * A single static assignment variable. diff --git a/python/ql/lib/semmle/python/SelfAttribute.qll b/python/ql/lib/semmle/python/SelfAttribute.qll index 01a110999ba..90ef2b38401 100644 --- a/python/ql/lib/semmle/python/SelfAttribute.qll +++ b/python/ql/lib/semmle/python/SelfAttribute.qll @@ -5,6 +5,7 @@ import python private import semmle.python.pointsto.Filters +private import LegacyPointsTo /** * An attribute access where the left hand side of the attribute expression diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index e1290b7758c..f3943f53f86 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.ImportStar private import semmle.python.dataflow.new.TypeTracking private import semmle.python.dataflow.new.internal.DataFlowPrivate +private import semmle.python.essa.SsaDefinitions /** * Python modules and the way imports are resolved are... complicated. Here's a crash course in how diff --git a/python/ql/lib/semmle/python/dataflow/old/Configuration.qll b/python/ql/lib/semmle/python/dataflow/old/Configuration.qll index 7d03e6c562f..f0e33169cf2 100644 --- a/python/ql/lib/semmle/python/dataflow/old/Configuration.qll +++ b/python/ql/lib/semmle/python/dataflow/old/Configuration.qll @@ -1,6 +1,6 @@ import python import semmle.python.dataflow.TaintTracking -private import semmle.python.objects.ObjectInternal +private import LegacyPointsTo private import semmle.python.dataflow.Implementation module TaintTracking { diff --git a/python/ql/lib/semmle/python/dataflow/old/Files.qll b/python/ql/lib/semmle/python/dataflow/old/Files.qll index 3439e559efa..18537768445 100644 --- a/python/ql/lib/semmle/python/dataflow/old/Files.qll +++ b/python/ql/lib/semmle/python/dataflow/old/Files.qll @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo import semmle.python.dataflow.TaintTracking class OpenFile extends TaintKind { diff --git a/python/ql/lib/semmle/python/dataflow/old/Implementation.qll b/python/ql/lib/semmle/python/dataflow/old/Implementation.qll index 83476db803c..eb7e5fdc9a5 100644 --- a/python/ql/lib/semmle/python/dataflow/old/Implementation.qll +++ b/python/ql/lib/semmle/python/dataflow/old/Implementation.qll @@ -1,7 +1,6 @@ import python private import LegacyPointsTo import semmle.python.dataflow.TaintTracking -private import semmle.python.objects.ObjectInternal private import semmle.python.pointsto.Filters as Filters import semmle.python.dataflow.Legacy diff --git a/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll b/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll index 2ca9be0dfb9..0eeb103ee55 100644 --- a/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll +++ b/python/ql/lib/semmle/python/dataflow/old/StateTracking.qll @@ -9,9 +9,7 @@ */ import python -private import semmle.python.pointsto.PointsTo -private import semmle.python.pointsto.PointsToContext -private import semmle.python.objects.ObjectInternal +private import LegacyPointsTo /** A state that should be tracked. */ abstract class TrackableState extends string { diff --git a/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll b/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll index 15459a31043..8dfa344f458 100644 --- a/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll +++ b/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll @@ -89,7 +89,6 @@ import python private import LegacyPointsTo private import semmle.python.pointsto.Filters as Filters -private import semmle.python.objects.ObjectInternal private import semmle.python.dataflow.Implementation import semmle.python.dataflow.Configuration diff --git a/python/ql/lib/semmle/python/dependencies/DependencyKind.qll b/python/ql/lib/semmle/python/dependencies/DependencyKind.qll index 2e4fab1af0b..4ceda85ff41 100644 --- a/python/ql/lib/semmle/python/dependencies/DependencyKind.qll +++ b/python/ql/lib/semmle/python/dependencies/DependencyKind.qll @@ -1,4 +1,5 @@ import semmle.python.dependencies.Dependencies +private import LegacyPointsTo /** * A library describing an abstract mechanism for representing dependency categories. diff --git a/python/ql/lib/semmle/python/dependencies/TechInventory.qll b/python/ql/lib/semmle/python/dependencies/TechInventory.qll index 20a938b86d0..2c29a05c48b 100644 --- a/python/ql/lib/semmle/python/dependencies/TechInventory.qll +++ b/python/ql/lib/semmle/python/dependencies/TechInventory.qll @@ -1,6 +1,7 @@ import python import semmle.python.dependencies.Dependencies import semmle.python.dependencies.DependencyKind +private import LegacyPointsTo /** * Combine the source-file and package into a single string: diff --git a/python/ql/lib/semmle/python/essa/Definitions.qll b/python/ql/lib/semmle/python/essa/Definitions.qll index 9c0df69c28e..d9426fc5612 100644 --- a/python/ql/lib/semmle/python/essa/Definitions.qll +++ b/python/ql/lib/semmle/python/essa/Definitions.qll @@ -1,5 +1,4 @@ import python - /* * Classification of variables. These should be non-overlapping and complete. * @@ -12,6 +11,9 @@ import python * Escaping globals -- Global variables that have definitions and at least one of those definitions is in another scope. */ +private import LegacyPointsTo +private import semmle.python.essa.SsaDefinitions + /** A source language variable, to be converted into a set of SSA variables. */ abstract class SsaSourceVariable extends @py_variable { SsaSourceVariable() { diff --git a/python/ql/lib/semmle/python/essa/Essa.qll b/python/ql/lib/semmle/python/essa/Essa.qll index cf2aca1e2ac..1b83f8df6ac 100644 --- a/python/ql/lib/semmle/python/essa/Essa.qll +++ b/python/ql/lib/semmle/python/essa/Essa.qll @@ -6,6 +6,8 @@ import python private import SsaCompute import semmle.python.essa.Definitions private import semmle.python.internal.CachedStages +private import LegacyPointsTo +private import semmle.python.essa.SsaDefinitions /** An (enhanced) SSA variable derived from `SsaSourceVariable`. */ class EssaVariable extends TEssaDefinition { diff --git a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll index 0c1c8836f4e..2b15f1a2ab2 100644 --- a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll +++ b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll @@ -5,6 +5,7 @@ import python private import semmle.python.internal.CachedStages +private import LegacyPointsTo cached module SsaSource { diff --git a/python/ql/lib/semmle/python/libraries/Zope.qll b/python/ql/lib/semmle/python/libraries/Zope.qll index fea3cecf418..defea3e4720 100644 --- a/python/ql/lib/semmle/python/libraries/Zope.qll +++ b/python/ql/lib/semmle/python/libraries/Zope.qll @@ -1,7 +1,7 @@ /** Utilities for handling the zope libraries */ import python -private import semmle.python.pointsto.PointsTo +private import LegacyPointsTo /** A method that belongs to a sub-class of `zope.interface.Interface` */ class ZopeInterfaceMethodValue extends PythonFunctionValue { diff --git a/python/ql/lib/semmle/python/objects/Constants.qll b/python/ql/lib/semmle/python/objects/Constants.qll index 31b63399ff4..49221df5b67 100644 --- a/python/ql/lib/semmle/python/objects/Constants.qll +++ b/python/ql/lib/semmle/python/objects/Constants.qll @@ -5,6 +5,7 @@ private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.MRO private import semmle.python.pointsto.PointsToContext private import semmle.python.types.Builtins +private import semmle.python.objects.ObjectAPI /** * A constant. diff --git a/python/ql/lib/semmle/python/objects/Descriptors.qll b/python/ql/lib/semmle/python/objects/Descriptors.qll index 2c18708e16a..5cb855ee5ca 100644 --- a/python/ql/lib/semmle/python/objects/Descriptors.qll +++ b/python/ql/lib/semmle/python/objects/Descriptors.qll @@ -5,6 +5,7 @@ private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.PointsToContext private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins +private import semmle.python.pointsto.Context /** A property object. */ class PropertyInternal extends ObjectInternal, TProperty { diff --git a/python/ql/lib/semmle/python/objects/Instances.qll b/python/ql/lib/semmle/python/objects/Instances.qll index 0b4187b6928..2ae00502902 100644 --- a/python/ql/lib/semmle/python/objects/Instances.qll +++ b/python/ql/lib/semmle/python/objects/Instances.qll @@ -5,6 +5,8 @@ private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.MRO private import semmle.python.pointsto.PointsToContext private import semmle.python.types.Builtins +private import semmle.python.pointsto.Context +private import semmle.python.pointsto.Base /** A class representing instances */ abstract class InstanceObject extends ObjectInternal { diff --git a/python/ql/lib/semmle/python/objects/Modules.qll b/python/ql/lib/semmle/python/objects/Modules.qll index e523ad0b70a..8c5653fa2a3 100644 --- a/python/ql/lib/semmle/python/objects/Modules.qll +++ b/python/ql/lib/semmle/python/objects/Modules.qll @@ -5,6 +5,7 @@ private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.MRO private import semmle.python.pointsto.PointsToContext private import semmle.python.types.Builtins +private import semmle.python.types.ImportTime /** A class representing modules */ abstract class ModuleObjectInternal extends ObjectInternal { diff --git a/python/ql/lib/semmle/python/objects/ObjectAPI.qll b/python/ql/lib/semmle/python/objects/ObjectAPI.qll index 45247c5d9d4..a5d4d91cc7a 100644 --- a/python/ql/lib/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/lib/semmle/python/objects/ObjectAPI.qll @@ -6,9 +6,6 @@ import python private import LegacyPointsTo private import TObject -private import semmle.python.objects.ObjectInternal -private import semmle.python.pointsto.PointsTo -private import semmle.python.pointsto.PointsToContext private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins diff --git a/python/ql/lib/semmle/python/objects/TObject.qll b/python/ql/lib/semmle/python/objects/TObject.qll index 12b4dc901c3..c041827ff5a 100644 --- a/python/ql/lib/semmle/python/objects/TObject.qll +++ b/python/ql/lib/semmle/python/objects/TObject.qll @@ -6,6 +6,7 @@ private import semmle.python.objects.ObjectInternal private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.PointsToContext private import semmle.python.internal.CachedStages +private import semmle.python.pointsto.Context /** * Internal type backing `ObjectInternal` and `Value` diff --git a/python/ql/lib/semmle/python/pointsto/Base.qll b/python/ql/lib/semmle/python/pointsto/Base.qll index 56dc633eb9c..c3f10778cda 100644 --- a/python/ql/lib/semmle/python/pointsto/Base.qll +++ b/python/ql/lib/semmle/python/pointsto/Base.qll @@ -12,6 +12,8 @@ import python import semmle.python.essa.SsaDefinitions private import semmle.python.types.Builtins private import semmle.python.internal.CachedStages +private import semmle.python.types.Object +private import semmle.python.types.ClassObject /* * The following predicates exist in order to provide diff --git a/python/ql/lib/semmle/python/pointsto/CallGraph.qll b/python/ql/lib/semmle/python/pointsto/CallGraph.qll index da225439588..734a5540254 100644 --- a/python/ql/lib/semmle/python/pointsto/CallGraph.qll +++ b/python/ql/lib/semmle/python/pointsto/CallGraph.qll @@ -11,6 +11,8 @@ import python private import semmle.python.pointsto.PointsToContext +private import semmle.python.types.FunctionObject +private import semmle.python.pointsto.Context private newtype TTInvocation = TInvocation(FunctionObject f, Context c) { diff --git a/python/ql/lib/semmle/python/pointsto/PointsTo.qll b/python/ql/lib/semmle/python/pointsto/PointsTo.qll index 56e8f6d6a63..ce1485c3f3d 100644 --- a/python/ql/lib/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/lib/semmle/python/pointsto/PointsTo.qll @@ -7,6 +7,11 @@ private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins private import semmle.python.types.Extensions private import semmle.python.internal.CachedStages +private import semmle.python.types.Object +private import semmle.python.types.FunctionObject +private import semmle.python.types.ClassObject +private import semmle.python.pointsto.Base +private import semmle.python.types.ImportTime /* Use this version for speed */ class CfgOrigin extends @py_object { diff --git a/python/ql/lib/semmle/python/pointsto/PointsToContext.qll b/python/ql/lib/semmle/python/pointsto/PointsToContext.qll index d68ce93e576..fb005b8f046 100644 --- a/python/ql/lib/semmle/python/pointsto/PointsToContext.qll +++ b/python/ql/lib/semmle/python/pointsto/PointsToContext.qll @@ -1,6 +1,8 @@ import python private import semmle.python.pointsto.PointsTo private import semmle.python.objects.ObjectInternal +private import semmle.python.types.ImportTime +private import semmle.python.types.Version /* * A note on 'cost'. Cost doesn't represent the cost to compute, diff --git a/python/ql/lib/semmle/python/types/Builtins.qll b/python/ql/lib/semmle/python/types/Builtins.qll index e6a21e1b717..796397f72cd 100644 --- a/python/ql/lib/semmle/python/types/Builtins.qll +++ b/python/ql/lib/semmle/python/types/Builtins.qll @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo class Builtin extends @py_cobject { Builtin() { diff --git a/python/ql/lib/semmle/python/types/ClassObject.qll b/python/ql/lib/semmle/python/types/ClassObject.qll index 6954a83463c..fbea3acdb5b 100644 --- a/python/ql/lib/semmle/python/types/ClassObject.qll +++ b/python/ql/lib/semmle/python/types/ClassObject.qll @@ -6,6 +6,7 @@ private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins private import semmle.python.objects.ObjectInternal +private import semmle.python.types.ImportTime /** * A class whose instances represents Python classes. diff --git a/python/ql/lib/semmle/python/types/Descriptors.qll b/python/ql/lib/semmle/python/types/Descriptors.qll index 6a5743c444a..7a81142a4f2 100644 --- a/python/ql/lib/semmle/python/types/Descriptors.qll +++ b/python/ql/lib/semmle/python/types/Descriptors.qll @@ -1,5 +1,8 @@ import python private import semmle.python.objects.ObjectInternal +private import semmle.python.types.Object +private import semmle.python.types.FunctionObject +private import semmle.python.pointsto.Context /** A class method object. Either a decorated function or an explicit call to classmethod(f) */ class ClassMethodObject extends Object { diff --git a/python/ql/lib/semmle/python/types/Extensions.qll b/python/ql/lib/semmle/python/types/Extensions.qll index f6c824f9ab2..d292f568fb9 100644 --- a/python/ql/lib/semmle/python/types/Extensions.qll +++ b/python/ql/lib/semmle/python/types/Extensions.qll @@ -16,6 +16,7 @@ private import semmle.python.pointsto.PointsToContext private import semmle.python.objects.TObject /* Make ObjectInternal visible to save extra imports in user code */ import semmle.python.objects.ObjectInternal +import semmle.python.pointsto.Context abstract class PointsToExtension extends @py_flow_node { string toString() { result = "PointsToExtension with missing toString" } diff --git a/python/ql/lib/semmle/python/types/FunctionObject.qll b/python/ql/lib/semmle/python/types/FunctionObject.qll index 72ddb9411fb..7ff0f37ca9a 100644 --- a/python/ql/lib/semmle/python/types/FunctionObject.qll +++ b/python/ql/lib/semmle/python/types/FunctionObject.qll @@ -1,10 +1,7 @@ import python private import LegacyPointsTo -import semmle.python.types.Exceptions -private import semmle.python.pointsto.PointsTo private import semmle.python.objects.Callables private import semmle.python.libraries.Zope -private import semmle.python.objects.ObjectInternal private import semmle.python.types.Builtins /** A function object, whether written in Python or builtin */ diff --git a/python/ql/lib/semmle/python/types/ModuleKind.qll b/python/ql/lib/semmle/python/types/ModuleKind.qll index ef44d80701e..03b64396bae 100644 --- a/python/ql/lib/semmle/python/types/ModuleKind.qll +++ b/python/ql/lib/semmle/python/types/ModuleKind.qll @@ -1,4 +1,5 @@ import python +private import semmle.python.types.ModuleObject private predicate is_normal_module(ModuleObject m) { m instanceof BuiltinModuleObject diff --git a/python/ql/lib/semmle/python/types/ModuleObject.qll b/python/ql/lib/semmle/python/types/ModuleObject.qll index 2e6d3863801..0dfa96e7050 100644 --- a/python/ql/lib/semmle/python/types/ModuleObject.qll +++ b/python/ql/lib/semmle/python/types/ModuleObject.qll @@ -2,6 +2,9 @@ import python private import semmle.python.pointsto.PointsTo private import semmle.python.objects.ObjectInternal private import semmle.python.types.ModuleKind +private import semmle.python.types.Object +private import semmle.python.types.ClassObject +private import semmle.python.objects.ObjectAPI abstract class ModuleObject extends Object { ModuleValue theModule() { diff --git a/python/ql/lib/semmle/python/types/Object.qll b/python/ql/lib/semmle/python/types/Object.qll index 1e0868648be..4c88f46dde8 100644 --- a/python/ql/lib/semmle/python/types/Object.qll +++ b/python/ql/lib/semmle/python/types/Object.qll @@ -1,6 +1,5 @@ import python private import LegacyPointsTo -private import semmle.python.objects.ObjectInternal private import semmle.python.types.Builtins private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/values/StringAttributes.qll b/python/ql/lib/semmle/python/values/StringAttributes.qll index e94540dbf20..e914730ef8b 100644 --- a/python/ql/lib/semmle/python/values/StringAttributes.qll +++ b/python/ql/lib/semmle/python/values/StringAttributes.qll @@ -1,8 +1,5 @@ import python private import LegacyPointsTo -private import semmle.python.types.Object -private import semmle.python.types.ClassObject -private import semmle.python.types.FunctionObject predicate string_attribute_all(ControlFlowNodeWithPointsTo n, string attr) { (n.getNode() instanceof Unicode or n.getNode() instanceof Bytes) and diff --git a/python/ql/src/Expressions/ContainsNonContainer.ql b/python/ql/src/Expressions/ContainsNonContainer.ql index fd2123dd436..de8c3879567 100644 --- a/python/ql/src/Expressions/ContainsNonContainer.ql +++ b/python/ql/src/Expressions/ContainsNonContainer.ql @@ -13,7 +13,6 @@ import python private import LegacyPointsTo -import semmle.python.pointsto.PointsTo predicate rhs_in_expr(ControlFlowNode rhs, Compare cmp) { exists(Cmpop op, int i | cmp.getOp(i) = op and cmp.getComparator(i) = rhs.getNode() | diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index 1ed4534bd23..052407f7111 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -3,6 +3,7 @@ import python private import LegacyPointsTo private import semmle.python.objects.ObjectInternal +private import semmle.python.objects.ObjectAPI /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { diff --git a/python/ql/src/Statements/RedundantAssignment.ql b/python/ql/src/Statements/RedundantAssignment.ql index 357364c41b2..e3f58995fa1 100644 --- a/python/ql/src/Statements/RedundantAssignment.ql +++ b/python/ql/src/Statements/RedundantAssignment.ql @@ -14,6 +14,7 @@ import python private import LegacyPointsTo +private import semmle.python.objects.ObjectAPI predicate assignment(AssignStmt a, Expr left, Expr right) { a.getATarget() = left and a.getValue() = right diff --git a/python/ql/src/Variables/UndefinedGlobal.ql b/python/ql/src/Variables/UndefinedGlobal.ql index 3ea1c0d38eb..bfe816d5c58 100644 --- a/python/ql/src/Variables/UndefinedGlobal.ql +++ b/python/ql/src/Variables/UndefinedGlobal.ql @@ -14,7 +14,6 @@ import python private import LegacyPointsTo import Variables.MonkeyPatched import Loop -import semmle.python.pointsto.PointsTo predicate guarded_against_name_error(Name u) { exists(Try t | t.getBody().getAnItem().contains(u) | diff --git a/python/ql/src/Variables/UninitializedLocal.ql b/python/ql/src/Variables/UninitializedLocal.ql index d4d94f5a4f3..48332e01af3 100644 --- a/python/ql/src/Variables/UninitializedLocal.ql +++ b/python/ql/src/Variables/UninitializedLocal.ql @@ -14,7 +14,6 @@ import python private import LegacyPointsTo import Undefined -import semmle.python.pointsto.PointsTo predicate uninitialized_local(NameNode use) { exists(FastLocalVariable local | use.uses(local) or use.deletes(local) | diff --git a/python/ql/src/analysis/Efficiency.ql b/python/ql/src/analysis/Efficiency.ql index 37cb5c97387..d8ed85f2a2b 100644 --- a/python/ql/src/analysis/Efficiency.ql +++ b/python/ql/src/analysis/Efficiency.ql @@ -5,8 +5,6 @@ import python private import LegacyPointsTo -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext predicate trivial(ControlFlowNode f) { f.getNode() instanceof Parameter From f0465f441f3f782656a6efd71e3092fc7b95f711 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 16:44:25 +0000 Subject: [PATCH 02/22] Python: Get rid of some `get...Object` methods This frees `Class.qll`, `Exprs.qll`, and `Function.qll` from the clutches of points-to. For the somewhat complicated setup with `getLiteralObject` (an abstract method), I opted for a slightly ugly but workable solution of just defining a predicate on `ImmutableLiteral` that inlines each predicate body, special-cased to the specific instance to which it applies. --- python/ql/lib/LegacyPointsTo.qll | 63 +++++++++++++++++++ python/ql/lib/semmle/python/Class.qll | 3 - python/ql/lib/semmle/python/Exprs.qll | 43 +------------ python/ql/lib/semmle/python/Function.qll | 3 - .../lib/semmle/python/types/ClassObject.qll | 2 +- .../2/extractor-tests/normalise/Numbers.ql | 3 +- .../test/2/library-tests/objects/Literals.ql | 3 +- .../ql/test/library-tests/objects/Literals.ql | 3 +- 8 files changed, 72 insertions(+), 51 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index bc2a6b7804a..cfa73bf47c4 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -221,3 +221,66 @@ class ModuleWithPointsTo extends Module { override string getAQlClass() { none() } } + +/** + * An extension of `Function` that provides points-to related methods. + */ +class FunctionWithPointsTo extends Function { + /** Gets the FunctionObject corresponding to this function */ + FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() } + + override string getAQlClass() { none() } +} + +/** + * An extension of `Class` that provides points-to related methods. + */ +class ClassWithPointsTo extends Class { + /** Gets the ClassObject corresponding to this class */ + ClassObject getClassObject() { result.getOrigin() = this.getParent() } + + override string getAQlClass() { none() } +} + +Object getLiteralObject(ImmutableLiteral l) { + l instanceof IntegerLiteral and + ( + py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, l.(Num).getN()) + or + py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, l.(Num).getN()) + ) + or + l instanceof FloatLiteral and + py_cobjecttypes(result, theFloatType()) and + py_cobjectnames(result, l.(Num).getN()) + or + l instanceof ImaginaryLiteral and + py_cobjecttypes(result, theComplexType()) and + py_cobjectnames(result, l.(Num).getN()) + or + l instanceof NegativeIntegerLiteral and + ( + (py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and + py_cobjectnames(result, "-" + l.(UnaryExpr).getOperand().(IntegerLiteral).getN()) + ) + or + l instanceof Bytes and + py_cobjecttypes(result, theBytesType()) and + py_cobjectnames(result, l.(Bytes).quotedString()) + or + l instanceof Unicode and + py_cobjecttypes(result, theUnicodeType()) and + py_cobjectnames(result, l.(Unicode).quotedString()) + or + l instanceof True and + name_consts(l, "True") and + result = theTrueObject() + or + l instanceof False and + name_consts(l, "False") and + result = theFalseObject() + or + l instanceof None and + name_consts(l, "None") and + result = theNoneObject() +} diff --git a/python/ql/lib/semmle/python/Class.qll b/python/ql/lib/semmle/python/Class.qll index 58a6504b547..dd7da9ee041 100644 --- a/python/ql/lib/semmle/python/Class.qll +++ b/python/ql/lib/semmle/python/Class.qll @@ -141,9 +141,6 @@ class Class extends Class_, Scope, AstNode { /** Gets the metaclass expression */ Expr getMetaClass() { result = this.getParent().getMetaClass() } - /** Gets the ClassObject corresponding to this class */ - ClassObject getClassObject() { result.getOrigin() = this.getParent() } - /** Gets the nth base of this class definition. */ Expr getBase(int index) { result = this.getParent().getBase(index) } diff --git a/python/ql/lib/semmle/python/Exprs.qll b/python/ql/lib/semmle/python/Exprs.qll index e5ee2bdb28c..203e63f611f 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -240,17 +240,12 @@ class Bytes extends StringLiteral { /* syntax: b"hello" */ Bytes() { not this.isUnicode() } - override Object getLiteralObject() { - py_cobjecttypes(result, theBytesType()) and - py_cobjectnames(result, this.quotedString()) - } - /** * The extractor puts quotes into the name of each string (to prevent "0" clashing with 0). * The following predicate help us match up a string/byte literals in the source * which the equivalent object. */ - private string quotedString() { + string quotedString() { exists(string b_unquoted | b_unquoted = this.getS() | result = "b'" + b_unquoted + "'") } } @@ -266,8 +261,6 @@ class Ellipsis extends Ellipsis_ { * Consists of string (both unicode and byte) literals and numeric literals. */ abstract class ImmutableLiteral extends Expr { - abstract Object getLiteralObject(); - abstract boolean booleanValue(); } @@ -292,12 +285,6 @@ class IntegerLiteral extends Num { override string toString() { result = "IntegerLiteral" } - override Object getLiteralObject() { - py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, this.getN()) - or - py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, this.getN()) - } - override boolean booleanValue() { this.getValue() = 0 and result = false or @@ -317,10 +304,6 @@ class FloatLiteral extends Num { override string toString() { result = "FloatLiteral" } - override Object getLiteralObject() { - py_cobjecttypes(result, theFloatType()) and py_cobjectnames(result, this.getN()) - } - override boolean booleanValue() { this.getValue() = 0.0 and result = false or @@ -343,10 +326,6 @@ class ImaginaryLiteral extends Num { override string toString() { result = "ImaginaryLiteral" } - override Object getLiteralObject() { - py_cobjecttypes(result, theComplexType()) and py_cobjectnames(result, this.getN()) - } - override boolean booleanValue() { this.getValue() = 0.0 and result = false or @@ -365,11 +344,6 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr { override boolean booleanValue() { result = this.getOperand().(IntegerLiteral).booleanValue() } - override Object getLiteralObject() { - (py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and - py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN()) - } - /** * Gets the (integer) value of this constant. Will not return a result if the value does not fit into * a 32 bit signed value @@ -385,11 +359,6 @@ class Unicode extends StringLiteral { /* syntax: "hello" */ Unicode() { this.isUnicode() } - override Object getLiteralObject() { - py_cobjecttypes(result, theUnicodeType()) and - py_cobjectnames(result, this.quotedString()) - } - /** * Gets the quoted representation fo this string. * @@ -593,12 +562,10 @@ class StringLiteral extends Str_, ImmutableLiteral { this.getText() != "" and result = true } - override Object getLiteralObject() { none() } - override string toString() { result = "StringLiteral" } } -private predicate name_consts(Name_ n, string id) { +predicate name_consts(Name_ n, string id) { exists(Variable v | py_variables(v, n) and id = v.getId() | id = "True" or id = "False" or id = "None" ) @@ -627,8 +594,6 @@ class True extends BooleanLiteral { /* syntax: True */ True() { name_consts(this, "True") } - override Object getLiteralObject() { name_consts(this, "True") and result = theTrueObject() } - override boolean booleanValue() { result = true } } @@ -637,8 +602,6 @@ class False extends BooleanLiteral { /* syntax: False */ False() { name_consts(this, "False") } - override Object getLiteralObject() { name_consts(this, "False") and result = theFalseObject() } - override boolean booleanValue() { result = false } } @@ -647,8 +610,6 @@ class None extends NameConstant { /* syntax: None */ None() { name_consts(this, "None") } - override Object getLiteralObject() { name_consts(this, "None") and result = theNoneObject() } - override boolean booleanValue() { result = false } } diff --git a/python/ql/lib/semmle/python/Function.qll b/python/ql/lib/semmle/python/Function.qll index 589d7f47161..a5d122c3de7 100644 --- a/python/ql/lib/semmle/python/Function.qll +++ b/python/ql/lib/semmle/python/Function.qll @@ -87,9 +87,6 @@ class Function extends Function_, Scope, AstNode { /** Gets the metrics for this function */ FunctionMetrics getMetrics() { result = this } - /** Gets the FunctionObject corresponding to this function */ - FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() } - /** * Whether this function is a procedure, that is, it has no explicit return statement and always returns None. * Note that generator and async functions are not procedures as they return generators and coroutines respectively. diff --git a/python/ql/lib/semmle/python/types/ClassObject.qll b/python/ql/lib/semmle/python/types/ClassObject.qll index fbea3acdb5b..8607141f16f 100644 --- a/python/ql/lib/semmle/python/types/ClassObject.qll +++ b/python/ql/lib/semmle/python/types/ClassObject.qll @@ -89,7 +89,7 @@ class ClassObject extends Object { } /** Gets the scope associated with this class, if it is not a builtin class */ - Class getPyClass() { result.getClassObject() = this } + ClassWithPointsTo getPyClass() { result.getClassObject() = this } /** Returns an attribute declared on this class (not on a super-class) */ Object declaredAttribute(string name) { diff --git a/python/ql/test/2/extractor-tests/normalise/Numbers.ql b/python/ql/test/2/extractor-tests/normalise/Numbers.ql index 2a770600279..9447141ab6a 100644 --- a/python/ql/test/2/extractor-tests/normalise/Numbers.ql +++ b/python/ql/test/2/extractor-tests/normalise/Numbers.ql @@ -7,10 +7,11 @@ */ import python +private import LegacyPointsTo from NumericObject n where - exists(IntegerLiteral i | i.getLiteralObject() = n | + exists(IntegerLiteral i | getLiteralObject(i) = n | i.getEnclosingModule().getFile().getShortName() = "test.py" ) select n.toString(), n.repr() diff --git a/python/ql/test/2/library-tests/objects/Literals.ql b/python/ql/test/2/library-tests/objects/Literals.ql index a7f10b358ff..d5aee013f25 100644 --- a/python/ql/test/2/library-tests/objects/Literals.ql +++ b/python/ql/test/2/library-tests/objects/Literals.ql @@ -1,5 +1,6 @@ /* Test that there are no literals that do not have a corresponding object. */ import python +private import LegacyPointsTo string repr(Expr e) { result = e.(Num).getN() or @@ -8,5 +9,5 @@ string repr(Expr e) { } from ImmutableLiteral l -where not exists(l.getLiteralObject()) +where not exists(getLiteralObject(l)) select l.getLocation().getStartLine(), repr(l) diff --git a/python/ql/test/library-tests/objects/Literals.ql b/python/ql/test/library-tests/objects/Literals.ql index a7f10b358ff..d5aee013f25 100644 --- a/python/ql/test/library-tests/objects/Literals.ql +++ b/python/ql/test/library-tests/objects/Literals.ql @@ -1,5 +1,6 @@ /* Test that there are no literals that do not have a corresponding object. */ import python +private import LegacyPointsTo string repr(Expr e) { result = e.(Num).getN() or @@ -8,5 +9,5 @@ string repr(Expr e) { } from ImmutableLiteral l -where not exists(l.getLiteralObject()) +where not exists(getLiteralObject(l)) select l.getLocation().getStartLine(), repr(l) From 0a4ec2ca10306e5c5cc0f3e21e7719352b3c0857 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 16:46:33 +0000 Subject: [PATCH 03/22] Python: Move some non-points-to methods out of points-to These methods were in `pointsto.Base` but did not actually interact with the points-to machinery directly, so they were easy to move out. --- .../ql/lib/semmle/python/essa/Definitions.qll | 11 +++++++++++ .../lib/semmle/python/essa/SsaDefinitions.qll | 7 +++++++ python/ql/lib/semmle/python/pointsto/Base.qll | 18 ------------------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/python/ql/lib/semmle/python/essa/Definitions.qll b/python/ql/lib/semmle/python/essa/Definitions.qll index d9426fc5612..17b4e622ea1 100644 --- a/python/ql/lib/semmle/python/essa/Definitions.qll +++ b/python/ql/lib/semmle/python/essa/Definitions.qll @@ -276,6 +276,17 @@ class ModuleVariable extends SsaSourceVariable instanceof GlobalVariable { override CallNode redefinedAtCallSite() { none() } } +/** Holds if `f` is an import of the form `from .[...] import ...` and the enclosing scope is an __init__ module */ +private predicate import_from_dot_in_init(ImportExprNode f) { + f.getScope() = any(Module m).getInitModule() and + ( + f.getNode().getLevel() = 1 and + not exists(f.getNode().getName()) + or + f.getNode().getImportedModuleName() = f.getEnclosingModule().getPackage().getName() + ) +} + class NonEscapingGlobalVariable extends ModuleVariable { NonEscapingGlobalVariable() { this instanceof GlobalVariable and diff --git a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll index 2b15f1a2ab2..b263287d05d 100644 --- a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll +++ b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll @@ -7,6 +7,13 @@ import python private import semmle.python.internal.CachedStages private import LegacyPointsTo +/** Hold if `expr` is a test (a branch) and `use` is within that test */ +predicate test_contains(ControlFlowNode expr, ControlFlowNode use) { + expr.getNode() instanceof Expr and + expr.isBranch() and + expr.getAChild*() = use +} + cached module SsaSource { /** Holds if `v` is used as the receiver in a method call. */ diff --git a/python/ql/lib/semmle/python/pointsto/Base.qll b/python/ql/lib/semmle/python/pointsto/Base.qll index c3f10778cda..bf159c4b559 100644 --- a/python/ql/lib/semmle/python/pointsto/Base.qll +++ b/python/ql/lib/semmle/python/pointsto/Base.qll @@ -44,24 +44,6 @@ private predicate class_defines_name(Class cls, string name) { exists(SsaVariable var | name = var.getId() and var.getAUse() = cls.getANormalExit()) } -/** Hold if `expr` is a test (a branch) and `use` is within that test */ -predicate test_contains(ControlFlowNode expr, ControlFlowNode use) { - expr.getNode() instanceof Expr and - expr.isBranch() and - expr.getAChild*() = use -} - -/** Holds if `f` is an import of the form `from .[...] import ...` and the enclosing scope is an __init__ module */ -predicate import_from_dot_in_init(ImportExprNode f) { - f.getScope() = any(Module m).getInitModule() and - ( - f.getNode().getLevel() = 1 and - not exists(f.getNode().getName()) - or - f.getNode().getImportedModuleName() = f.getEnclosingModule().getPackage().getName() - ) -} - /** Gets the pseudo-object representing the value referred to by an undefined variable */ Object undefinedVariable() { py_special_objects(result, "_semmle_undefined_value") } From 2732a652ab8475a5f099dbddd8e60424d552acc5 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 23:00:14 +0000 Subject: [PATCH 04/22] Python: Fix example snippets One might argue that these should be rewritten entirely to use more modern APIs, but for now I'll be content with just having them compile properly. --- python/ql/examples/snippets/call.ql | 1 + python/ql/examples/snippets/extend_class.ql | 1 + python/ql/examples/snippets/method_call.ql | 1 + python/ql/examples/snippets/mutualrecursion.ql | 1 + python/ql/examples/snippets/override_method.ql | 1 + python/ql/examples/snippets/recursion.ql | 1 + 6 files changed, 6 insertions(+) diff --git a/python/ql/examples/snippets/call.ql b/python/ql/examples/snippets/call.ql index b326024a33c..0c68bbd69b9 100644 --- a/python/ql/examples/snippets/call.ql +++ b/python/ql/examples/snippets/call.ql @@ -7,6 +7,7 @@ */ import python +private import LegacyPointsTo from Value len, CallNode call where len.getName() = "len" and len.getACall() = call diff --git a/python/ql/examples/snippets/extend_class.ql b/python/ql/examples/snippets/extend_class.ql index 805929ab709..8efc1b8241a 100644 --- a/python/ql/examples/snippets/extend_class.ql +++ b/python/ql/examples/snippets/extend_class.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ClassObject sub, ClassObject base where diff --git a/python/ql/examples/snippets/method_call.ql b/python/ql/examples/snippets/method_call.ql index f78a9e43be0..c331b7c8bef 100644 --- a/python/ql/examples/snippets/method_call.ql +++ b/python/ql/examples/snippets/method_call.ql @@ -7,6 +7,7 @@ */ import python +private import LegacyPointsTo from AstNode call, PythonFunctionValue method where diff --git a/python/ql/examples/snippets/mutualrecursion.ql b/python/ql/examples/snippets/mutualrecursion.ql index 0cd445b6e3b..040dbae99d4 100644 --- a/python/ql/examples/snippets/mutualrecursion.ql +++ b/python/ql/examples/snippets/mutualrecursion.ql @@ -7,6 +7,7 @@ */ import python +private import LegacyPointsTo from FunctionObject m, FunctionObject n where m != n and m.getACallee() = n and n.getACallee() = m diff --git a/python/ql/examples/snippets/override_method.ql b/python/ql/examples/snippets/override_method.ql index 2b601d59df7..40c2eed8531 100644 --- a/python/ql/examples/snippets/override_method.ql +++ b/python/ql/examples/snippets/override_method.ql @@ -7,6 +7,7 @@ */ import python +private import LegacyPointsTo from FunctionObject override, FunctionObject base where diff --git a/python/ql/examples/snippets/recursion.ql b/python/ql/examples/snippets/recursion.ql index b986a265db5..7e0770f3927 100644 --- a/python/ql/examples/snippets/recursion.ql +++ b/python/ql/examples/snippets/recursion.ql @@ -7,6 +7,7 @@ */ import python +private import LegacyPointsTo from PythonFunctionValue f where f.getACall().getScope() = f.getScope() From 5b63b4957cec4edbd13244b318ce912117c4a8df Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 23:06:26 +0000 Subject: [PATCH 05/22] Python: Fix query tests Mostly just adding `private import LegacyPointsTo`. Sometimes getting rid of other imports that are superceded by that module. --- python/ql/src/Classes/ClassAttributes.qll | 2 +- python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql | 1 + python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql | 1 + python/ql/src/Classes/InconsistentMRO.ql | 1 + python/ql/src/Classes/MaybeUndefinedClassAttribute.ql | 1 + python/ql/src/Classes/MutatingDescriptor.ql | 1 + python/ql/src/Classes/OverwritingAttributeInSuperClass.ql | 1 + python/ql/src/Classes/PropertyInOldStyleClass.ql | 1 + python/ql/src/Classes/ShouldBeContextManager.ql | 1 + python/ql/src/Classes/SlotsInOldStyleClass.ql | 1 + python/ql/src/Classes/SuperInOldStyleClass.ql | 1 + python/ql/src/Classes/UndefinedClassAttribute.ql | 1 + python/ql/src/Classes/UselessClass.ql | 1 + .../ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql | 1 + .../ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql | 1 + python/ql/src/Exceptions/IllegalExceptionHandlerType.ql | 1 + python/ql/src/Exceptions/IllegalRaise.ql | 1 + python/ql/src/Expressions/IsComparisons.qll | 2 -- python/ql/src/Expressions/NonPortableComparisonUsingIs.ql | 1 + python/ql/src/Expressions/RedundantComparison.qll | 1 + python/ql/src/Expressions/WrongNameForArgumentInCall.ql | 1 + python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql | 1 - python/ql/src/Expressions/WrongNumberArgumentsInCall.ql | 1 + python/ql/src/Functions/DeprecatedSliceMethod.ql | 1 + python/ql/src/Functions/IncorrectlyOverriddenMethod.ql | 1 + .../ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql | 1 + python/ql/src/Functions/IterReturnsNonIterator.ql | 1 + python/ql/src/Functions/OverlyComplexDelMethod.ql | 1 + python/ql/src/Functions/ReturnValueIgnored.ql | 2 +- python/ql/src/Imports/CyclicImport.ql | 1 + python/ql/src/Imports/ModuleImportsItself.ql | 1 + python/ql/src/Imports/ModuleLevelCyclicImport.ql | 1 + python/ql/src/Imports/UnintentionalImport.ql | 1 + .../Metrics/Dependencies/ExternalDependenciesSourceLinks.ql | 1 + python/ql/src/Metrics/DirectImports.ql | 1 + python/ql/src/Metrics/TransitiveImports.ql | 1 + python/ql/src/Statements/DocStrings.ql | 1 + python/ql/src/Statements/RedundantAssignment.ql | 1 - python/ql/src/Statements/SideEffectInAssert.ql | 1 + python/ql/src/Statements/TopLevelPrint.ql | 1 + python/ql/src/Statements/UnnecessaryDelete.ql | 1 + python/ql/src/Variables/Undefined.qll | 1 + python/ql/src/Variables/UndefinedPlaceHolder.ql | 1 + python/ql/src/Variables/UnusedParameter.ql | 1 + python/ql/src/analysis/CallGraphEfficiency.ql | 3 +-- python/ql/src/analysis/CallGraphMarginalEfficiency.ql | 3 +-- python/ql/src/analysis/ContextEfficiency.ql | 3 +-- python/ql/src/analysis/ContextMarginalEfficiency.ql | 3 +-- python/ql/src/analysis/CrossProjectDefinitions.qll | 2 +- python/ql/src/analysis/FailedInference.ql | 2 +- python/ql/src/analysis/TypeHierarchyFailure.ql | 1 + python/ql/src/meta/analysis-quality/CallGraphQuality.qll | 1 + 52 files changed, 49 insertions(+), 16 deletions(-) diff --git a/python/ql/src/Classes/ClassAttributes.qll b/python/ql/src/Classes/ClassAttributes.qll index 25a02627393..4063bc7042e 100644 --- a/python/ql/src/Classes/ClassAttributes.qll +++ b/python/ql/src/Classes/ClassAttributes.qll @@ -1,5 +1,5 @@ import python -private import semmle.python.pointsto.PointsTo +private import LegacyPointsTo /** A helper class for UndefinedClassAttribute.ql and MaybeUndefinedClassAttribute.ql */ class CheckClass extends ClassObject { diff --git a/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql b/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql index 947c547c050..478444eadc8 100644 --- a/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql +++ b/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo predicate does_nothing(PyFunctionObject f) { not exists(Stmt s | s.getScope() = f.getFunction() | diff --git a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql index f6829b237a8..14fa0a72647 100644 --- a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql +++ b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql @@ -13,6 +13,7 @@ import python import Equality +private import LegacyPointsTo predicate class_stores_to_attribute(ClassValue cls, SelfAttributeStore store, string name) { exists(FunctionValue f | diff --git a/python/ql/src/Classes/InconsistentMRO.ql b/python/ql/src/Classes/InconsistentMRO.ql index b479f86ec55..aa319d56114 100644 --- a/python/ql/src/Classes/InconsistentMRO.ql +++ b/python/ql/src/Classes/InconsistentMRO.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo ClassObject left_base(ClassObject type, ClassObject base) { exists(int i | i > 0 and type.getBaseType(i) = base and result = type.getBaseType(i - 1)) diff --git a/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql b/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql index 9818aaece3c..6c4138f4f57 100644 --- a/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql +++ b/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql @@ -12,6 +12,7 @@ import python import ClassAttributes +private import LegacyPointsTo predicate guarded_by_other_attribute(SelfAttributeRead a, CheckClass c) { c.sometimesDefines(a.getName()) and diff --git a/python/ql/src/Classes/MutatingDescriptor.ql b/python/ql/src/Classes/MutatingDescriptor.ql index aad468f8e3c..c69f8868fd2 100644 --- a/python/ql/src/Classes/MutatingDescriptor.ql +++ b/python/ql/src/Classes/MutatingDescriptor.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo predicate mutates_descriptor(ClassObject cls, SelfAttributeStore s) { cls.isDescriptorType() and diff --git a/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql b/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql index 699e4387a14..89d33d54814 100644 --- a/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql +++ b/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo class InitCallStmt extends ExprStmt { InitCallStmt() { diff --git a/python/ql/src/Classes/PropertyInOldStyleClass.ql b/python/ql/src/Classes/PropertyInOldStyleClass.ql index 6e1b9a063c0..2fd7b1d14cf 100644 --- a/python/ql/src/Classes/PropertyInOldStyleClass.ql +++ b/python/ql/src/Classes/PropertyInOldStyleClass.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from PropertyObject prop, ClassObject cls where cls.declaredAttribute(_) = prop and not cls.failedInference() and not cls.isNewStyle() diff --git a/python/ql/src/Classes/ShouldBeContextManager.ql b/python/ql/src/Classes/ShouldBeContextManager.ql index 2423206e3cf..6aec0f0e0ab 100644 --- a/python/ql/src/Classes/ShouldBeContextManager.ql +++ b/python/ql/src/Classes/ShouldBeContextManager.ql @@ -14,6 +14,7 @@ */ import python +private import LegacyPointsTo from ClassValue c where not c.isBuiltin() and not c.isContextManager() and exists(c.declaredAttribute("__del__")) diff --git a/python/ql/src/Classes/SlotsInOldStyleClass.ql b/python/ql/src/Classes/SlotsInOldStyleClass.ql index bb229edc8d3..2f91a88cf64 100644 --- a/python/ql/src/Classes/SlotsInOldStyleClass.ql +++ b/python/ql/src/Classes/SlotsInOldStyleClass.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo from ClassObject c where not c.isNewStyle() and c.declaresAttribute("__slots__") and not c.failedInference() diff --git a/python/ql/src/Classes/SuperInOldStyleClass.ql b/python/ql/src/Classes/SuperInOldStyleClass.ql index deba0889449..a6a272b1b3b 100644 --- a/python/ql/src/Classes/SuperInOldStyleClass.ql +++ b/python/ql/src/Classes/SuperInOldStyleClass.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo predicate uses_of_super_in_old_style_class(Call s) { exists(Function f, ClassObject c | diff --git a/python/ql/src/Classes/UndefinedClassAttribute.ql b/python/ql/src/Classes/UndefinedClassAttribute.ql index 748c4681820..38dcb9b4a7d 100644 --- a/python/ql/src/Classes/UndefinedClassAttribute.ql +++ b/python/ql/src/Classes/UndefinedClassAttribute.ql @@ -12,6 +12,7 @@ import python import ClassAttributes +private import LegacyPointsTo predicate undefined_class_attribute(SelfAttributeRead a, CheckClass c, int line, string name) { name = a.getName() and diff --git a/python/ql/src/Classes/UselessClass.ql b/python/ql/src/Classes/UselessClass.ql index 7e33660dafc..740c74bf96d 100644 --- a/python/ql/src/Classes/UselessClass.ql +++ b/python/ql/src/Classes/UselessClass.ql @@ -13,6 +13,7 @@ */ import python +private import LegacyPointsTo predicate fewer_than_two_public_methods(Class cls, int methods) { (methods = 0 or methods = 1) and diff --git a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql index 1de99ebdbf6..5b50855dcdf 100644 --- a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql @@ -16,6 +16,7 @@ import python import Expressions.CallArgs +private import LegacyPointsTo from Call call, ClassValue cls, string name, FunctionValue init where diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql index 8518905f3a9..263a1a336a1 100644 --- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql @@ -15,6 +15,7 @@ import python import Expressions.CallArgs +private import LegacyPointsTo from Call call, ClassValue cls, string too, string should, int limit, FunctionValue init where diff --git a/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql b/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql index 2bf97b469ee..b5446dccbfc 100644 --- a/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql +++ b/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo from ExceptFlowNode ex, Value t, ClassValue c, ControlFlowNode origin, string what where diff --git a/python/ql/src/Exceptions/IllegalRaise.ql b/python/ql/src/Exceptions/IllegalRaise.ql index 04319e246ed..f9f263552b1 100644 --- a/python/ql/src/Exceptions/IllegalRaise.ql +++ b/python/ql/src/Exceptions/IllegalRaise.ql @@ -14,6 +14,7 @@ import python import Raising import Exceptions.NotImplemented +private import LegacyPointsTo from Raise r, ClassValue t where diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index 052407f7111..cb052ceca76 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -2,8 +2,6 @@ import python private import LegacyPointsTo -private import semmle.python.objects.ObjectInternal -private import semmle.python.objects.ObjectAPI /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { diff --git a/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql b/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql index 894cc78c8f4..d705bea0765 100644 --- a/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql +++ b/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql @@ -13,6 +13,7 @@ import python import IsComparisons +private import LegacyPointsTo from Compare comp, Cmpop op, ClassValue c where diff --git a/python/ql/src/Expressions/RedundantComparison.qll b/python/ql/src/Expressions/RedundantComparison.qll index a0d4f906501..dc40a89c784 100644 --- a/python/ql/src/Expressions/RedundantComparison.qll +++ b/python/ql/src/Expressions/RedundantComparison.qll @@ -1,6 +1,7 @@ /** Helper functions for queries that test redundant comparisons. */ import python +private import LegacyPointsTo /** A comparison where the left and right hand sides appear to be identical. */ class RedundantComparison extends Compare { diff --git a/python/ql/src/Expressions/WrongNameForArgumentInCall.ql b/python/ql/src/Expressions/WrongNameForArgumentInCall.ql index 21403c51c61..f267df13e19 100644 --- a/python/ql/src/Expressions/WrongNameForArgumentInCall.ql +++ b/python/ql/src/Expressions/WrongNameForArgumentInCall.ql @@ -16,6 +16,7 @@ import python import Expressions.CallArgs +private import LegacyPointsTo from Call call, FunctionObject func, string name where diff --git a/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql b/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql index d7b27e5c3d7..cf741d4cf64 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql @@ -15,7 +15,6 @@ import python import LegacyPointsTo -import semmle.python.objects.ObjectInternal import semmle.python.strings predicate string_format(BinaryExpr operation, StringLiteral str, Value args, AstNode origin) { diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql index bde54558c9b..35d9341fb05 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql @@ -13,6 +13,7 @@ */ import python +private import LegacyPointsTo import CallArgs from Call call, FunctionValue func, string too, string should, int limit diff --git a/python/ql/src/Functions/DeprecatedSliceMethod.ql b/python/ql/src/Functions/DeprecatedSliceMethod.ql index af596f704cd..3e9cdb681d9 100644 --- a/python/ql/src/Functions/DeprecatedSliceMethod.ql +++ b/python/ql/src/Functions/DeprecatedSliceMethod.ql @@ -10,6 +10,7 @@ */ import python +private import LegacyPointsTo predicate slice_method_name(string name) { name = "__getslice__" or name = "__setslice__" or name = "__delslice__" diff --git a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql index a4e3bd6e0ce..0a640d46239 100644 --- a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql @@ -14,6 +14,7 @@ import python import Expressions.CallArgs +private import LegacyPointsTo from Call call, FunctionValue func, FunctionValue overridden, string problem where diff --git a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql index 6b31795d94e..18cbddaff31 100644 --- a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql @@ -14,6 +14,7 @@ import python import Expressions.CallArgs +private import LegacyPointsTo from Call call, FunctionValue func, FunctionValue overriding, string problem where diff --git a/python/ql/src/Functions/IterReturnsNonIterator.ql b/python/ql/src/Functions/IterReturnsNonIterator.ql index 367332cf49a..08234726314 100644 --- a/python/ql/src/Functions/IterReturnsNonIterator.ql +++ b/python/ql/src/Functions/IterReturnsNonIterator.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo from ClassValue iterable, FunctionValue iter, ClassValue iterator where diff --git a/python/ql/src/Functions/OverlyComplexDelMethod.ql b/python/ql/src/Functions/OverlyComplexDelMethod.ql index b93dc4af3c3..d9fa3e750e6 100644 --- a/python/ql/src/Functions/OverlyComplexDelMethod.ql +++ b/python/ql/src/Functions/OverlyComplexDelMethod.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo from FunctionValue method where diff --git a/python/ql/src/Functions/ReturnValueIgnored.ql b/python/ql/src/Functions/ReturnValueIgnored.ql index d8f81534b8a..3716b989d89 100644 --- a/python/ql/src/Functions/ReturnValueIgnored.ql +++ b/python/ql/src/Functions/ReturnValueIgnored.ql @@ -14,7 +14,7 @@ */ import python -import semmle.python.objects.Callables +private import LegacyPointsTo predicate meaningful_return_value(Expr val) { val instanceof Name diff --git a/python/ql/src/Imports/CyclicImport.ql b/python/ql/src/Imports/CyclicImport.ql index 9e4a153a110..464d906db98 100644 --- a/python/ql/src/Imports/CyclicImport.ql +++ b/python/ql/src/Imports/CyclicImport.ql @@ -13,6 +13,7 @@ import python import Cyclic +private import LegacyPointsTo from ModuleValue m1, ModuleValue m2, Stmt imp where diff --git a/python/ql/src/Imports/ModuleImportsItself.ql b/python/ql/src/Imports/ModuleImportsItself.ql index 72d223da3db..97fb68791d1 100644 --- a/python/ql/src/Imports/ModuleImportsItself.ql +++ b/python/ql/src/Imports/ModuleImportsItself.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo predicate modules_imports_itself(ImportingStmt i, ModuleValue m) { i.getEnclosingModule() = m.getScope() and diff --git a/python/ql/src/Imports/ModuleLevelCyclicImport.ql b/python/ql/src/Imports/ModuleLevelCyclicImport.ql index 7d9b0cc31c7..7910cb76823 100644 --- a/python/ql/src/Imports/ModuleLevelCyclicImport.ql +++ b/python/ql/src/Imports/ModuleLevelCyclicImport.ql @@ -14,6 +14,7 @@ import python import Cyclic +private import LegacyPointsTo // This is a potentially crashing bug if // 1. the imports in the whole cycle are lexically outside a def (and so executed at import time) diff --git a/python/ql/src/Imports/UnintentionalImport.ql b/python/ql/src/Imports/UnintentionalImport.ql index 1faf3bb55f3..7b22865cd89 100644 --- a/python/ql/src/Imports/UnintentionalImport.ql +++ b/python/ql/src/Imports/UnintentionalImport.ql @@ -13,6 +13,7 @@ */ import python +private import LegacyPointsTo predicate import_star(ImportStar imp, ModuleValue exporter) { exporter.importedAs(imp.getImportedModuleName()) diff --git a/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql b/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql index 98bb4e63cc3..60dbcdcc7fc 100644 --- a/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql +++ b/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql @@ -8,6 +8,7 @@ import python import semmle.python.dependencies.TechInventory +private import LegacyPointsTo /* * This query creates the source links for the ExternalDependencies.ql query. diff --git a/python/ql/src/Metrics/DirectImports.ql b/python/ql/src/Metrics/DirectImports.ql index 240cd65e687..e383d4b3657 100644 --- a/python/ql/src/Metrics/DirectImports.ql +++ b/python/ql/src/Metrics/DirectImports.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ModuleValue m, int n where n = count(ModuleValue imp | imp = m.getAnImportedModule()) diff --git a/python/ql/src/Metrics/TransitiveImports.ql b/python/ql/src/Metrics/TransitiveImports.ql index a46a7a16302..364840fbcb9 100644 --- a/python/ql/src/Metrics/TransitiveImports.ql +++ b/python/ql/src/Metrics/TransitiveImports.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ModuleValue m, int n where n = count(ModuleValue imp | imp = m.getAnImportedModule+() and imp != m) diff --git a/python/ql/src/Statements/DocStrings.ql b/python/ql/src/Statements/DocStrings.ql index 903207f7ccb..d7df570a7ef 100644 --- a/python/ql/src/Statements/DocStrings.ql +++ b/python/ql/src/Statements/DocStrings.ql @@ -17,6 +17,7 @@ */ import python +private import LegacyPointsTo predicate needs_docstring(Scope s) { s.isPublic() and diff --git a/python/ql/src/Statements/RedundantAssignment.ql b/python/ql/src/Statements/RedundantAssignment.ql index e3f58995fa1..357364c41b2 100644 --- a/python/ql/src/Statements/RedundantAssignment.ql +++ b/python/ql/src/Statements/RedundantAssignment.ql @@ -14,7 +14,6 @@ import python private import LegacyPointsTo -private import semmle.python.objects.ObjectAPI predicate assignment(AssignStmt a, Expr left, Expr right) { a.getATarget() = left and a.getValue() = right diff --git a/python/ql/src/Statements/SideEffectInAssert.ql b/python/ql/src/Statements/SideEffectInAssert.ql index 92cb95d702b..902b6c4c9c1 100644 --- a/python/ql/src/Statements/SideEffectInAssert.ql +++ b/python/ql/src/Statements/SideEffectInAssert.ql @@ -13,6 +13,7 @@ */ import python +private import LegacyPointsTo predicate func_with_side_effects(Expr e) { exists(string name | name = e.(Attribute).getName() or name = e.(Name).getId() | diff --git a/python/ql/src/Statements/TopLevelPrint.ql b/python/ql/src/Statements/TopLevelPrint.ql index 2d481421b7e..12095f7a484 100644 --- a/python/ql/src/Statements/TopLevelPrint.ql +++ b/python/ql/src/Statements/TopLevelPrint.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo predicate main_eq_name(If i) { exists(Name n, StringLiteral m, Compare c | diff --git a/python/ql/src/Statements/UnnecessaryDelete.ql b/python/ql/src/Statements/UnnecessaryDelete.ql index 808a3f3a0d3..c7b80ecc66a 100644 --- a/python/ql/src/Statements/UnnecessaryDelete.ql +++ b/python/ql/src/Statements/UnnecessaryDelete.ql @@ -13,6 +13,7 @@ */ import python +private import LegacyPointsTo predicate isInsideLoop(AstNode node) { node.getParentNode() instanceof While diff --git a/python/ql/src/Variables/Undefined.qll b/python/ql/src/Variables/Undefined.qll index 58deee4dc59..42437a81340 100644 --- a/python/ql/src/Variables/Undefined.qll +++ b/python/ql/src/Variables/Undefined.qll @@ -1,6 +1,7 @@ import python import Loop import semmle.python.dataflow.TaintTracking +private import LegacyPointsTo /** A marker for "uninitialized". */ class Uninitialized extends TaintKind { diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index b0eeeda871a..11bf3b6d0be 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -13,6 +13,7 @@ import python import Variables.MonkeyPatched +private import LegacyPointsTo /* Local variable part */ predicate initialized_as_local(PlaceHolder use) { diff --git a/python/ql/src/Variables/UnusedParameter.ql b/python/ql/src/Variables/UnusedParameter.ql index 7228974b7c7..1efb984fd0b 100644 --- a/python/ql/src/Variables/UnusedParameter.ql +++ b/python/ql/src/Variables/UnusedParameter.ql @@ -14,6 +14,7 @@ import python import Definition +private import LegacyPointsTo predicate unused_parameter(FunctionValue f, LocalVariable v) { v.isParameter() and diff --git a/python/ql/src/analysis/CallGraphEfficiency.ql b/python/ql/src/analysis/CallGraphEfficiency.ql index 5e36823b8ac..3990b68ecc6 100644 --- a/python/ql/src/analysis/CallGraphEfficiency.ql +++ b/python/ql/src/analysis/CallGraphEfficiency.ql @@ -4,8 +4,7 @@ */ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo from int total_facts, int total_size, int depth, float efficiency where diff --git a/python/ql/src/analysis/CallGraphMarginalEfficiency.ql b/python/ql/src/analysis/CallGraphMarginalEfficiency.ql index 394bf379eeb..f2e931c411c 100644 --- a/python/ql/src/analysis/CallGraphMarginalEfficiency.ql +++ b/python/ql/src/analysis/CallGraphMarginalEfficiency.ql @@ -4,8 +4,7 @@ */ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo from int total_facts, int total_size, int depth, float efficiency where diff --git a/python/ql/src/analysis/ContextEfficiency.ql b/python/ql/src/analysis/ContextEfficiency.ql index 205091ba1e3..76ca78fc867 100644 --- a/python/ql/src/analysis/ContextEfficiency.ql +++ b/python/ql/src/analysis/ContextEfficiency.ql @@ -4,8 +4,7 @@ */ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo from int total_facts, int total_size, int depth, float efficiency where diff --git a/python/ql/src/analysis/ContextMarginalEfficiency.ql b/python/ql/src/analysis/ContextMarginalEfficiency.ql index 755ccad683c..c87de8c6ebe 100644 --- a/python/ql/src/analysis/ContextMarginalEfficiency.ql +++ b/python/ql/src/analysis/ContextMarginalEfficiency.ql @@ -4,8 +4,7 @@ */ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo int depth(ControlFlowNode f, Object value, ClassObject cls) { exists(PointsToContext ctx | diff --git a/python/ql/src/analysis/CrossProjectDefinitions.qll b/python/ql/src/analysis/CrossProjectDefinitions.qll index 84fd8215712..64b30f566f1 100644 --- a/python/ql/src/analysis/CrossProjectDefinitions.qll +++ b/python/ql/src/analysis/CrossProjectDefinitions.qll @@ -3,7 +3,7 @@ */ import python -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo private newtype TSymbol = TModule(Module m) or diff --git a/python/ql/src/analysis/FailedInference.ql b/python/ql/src/analysis/FailedInference.ql index 192cf696fbf..feae8fdc5ee 100644 --- a/python/ql/src/analysis/FailedInference.ql +++ b/python/ql/src/analysis/FailedInference.ql @@ -1,5 +1,5 @@ import python -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo from ClassValue cls, string reason where Types::failedInference(cls, reason) diff --git a/python/ql/src/analysis/TypeHierarchyFailure.ql b/python/ql/src/analysis/TypeHierarchyFailure.ql index c4c91005743..c6ad4be9822 100644 --- a/python/ql/src/analysis/TypeHierarchyFailure.ql +++ b/python/ql/src/analysis/TypeHierarchyFailure.ql @@ -8,6 +8,7 @@ */ import python +private import LegacyPointsTo from Class cls, string reason where exists(ClassObject c | c.getPyClass() = cls | c.failedInference(reason)) diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index a8e7a3b340a..679b39ddc8d 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -5,6 +5,7 @@ import python import meta.MetaMetrics +private import LegacyPointsTo newtype TTarget = TFunction(Function func) or From 85029bd77d4b83993ff3ec0d4fe76b9909c38073 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 23:07:25 +0000 Subject: [PATCH 06/22] Python: Fix Python 2 tests --- python/ql/test/2/extractor-tests/import_depth/test.ql | 1 + python/ql/test/2/extractor-tests/object_hash/Success.ql | 1 + .../ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql | 1 + python/ql/test/2/library-tests/ControlFlow/Exceptions/Known.ql | 1 + .../ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql | 1 + .../ql/test/2/library-tests/ControlFlow/Exceptions/Unknown.ql | 1 + python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql | 3 +-- python/ql/test/2/library-tests/PointsTo/metaclass/test.ql | 1 + python/ql/test/2/library-tests/classes/attr/class_attr.ql | 1 + python/ql/test/2/library-tests/classes/attr/class_has_attr.ql | 1 + python/ql/test/2/library-tests/classes/attr/list_attr.ql | 1 + python/ql/test/2/library-tests/classes/mro/mro.ql | 1 + .../test/2/library-tests/modules/general/moduleobject_test.ql | 1 + .../library-tests/modules/package_members/module_attributes.ql | 1 + .../2/library-tests/modules/package_members/module_exports.ql | 1 + .../library-tests/modules/package_members/module_import_as.ql | 1 + python/ql/test/2/library-tests/modules/usage/ModuleUsage.ql | 1 + python/ql/test/2/library-tests/types/classes/mro_test.ql | 1 + python/ql/test/2/library-tests/types/classes/new_style.ql | 1 + python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql | 1 + python/ql/test/2/library-tests/types/exceptions/Raises.ql | 1 + python/ql/test/2/library-tests/types/functions/Calls.ql | 1 + python/ql/test/2/library-tests/types/functions/Never.ql | 1 + python/ql/test/2/library-tests/types/functions/ReturnTypes.ql | 1 + .../test/2/library-tests/types/properties/BuiltinProperties.ql | 1 + 25 files changed, 25 insertions(+), 2 deletions(-) diff --git a/python/ql/test/2/extractor-tests/import_depth/test.ql b/python/ql/test/2/extractor-tests/import_depth/test.ql index ef626455fad..4f007e99468 100644 --- a/python/ql/test/2/extractor-tests/import_depth/test.ql +++ b/python/ql/test/2/extractor-tests/import_depth/test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m /* Exclude the builtins module as it has a different name under 2 and 3. */ diff --git a/python/ql/test/2/extractor-tests/object_hash/Success.ql b/python/ql/test/2/extractor-tests/object_hash/Success.ql index 9cff9ee4b73..55e38e56b93 100644 --- a/python/ql/test/2/extractor-tests/object_hash/Success.ql +++ b/python/ql/test/2/extractor-tests/object_hash/Success.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo where exists(theSysModuleObject()) select 1 diff --git a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql index 620944de5b9..60989ff8645 100644 --- a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql +++ b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ExceptFlowNode ex, Value val where ex.handledException(val, _, _) diff --git a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Known.ql b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Known.ql index 56498054f51..b773a172ee3 100644 --- a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Known.ql +++ b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Known.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r select r.getLocation().getStartLine(), r.toString(), r.getARaisedType().toString() diff --git a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql index f8e4a4b7dac..00cf5a7d2af 100644 --- a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql +++ b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ControlFlowNode r, ControlFlowNode s where diff --git a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Unknown.ql b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Unknown.ql index 29bad86bf0f..fe0fa6b0158 100644 --- a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Unknown.ql +++ b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Unknown.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r where r.raisesUnknownType() diff --git a/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql b/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql index e77849860c7..ba8df441caf 100644 --- a/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql +++ b/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql @@ -1,6 +1,5 @@ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo from ControlFlowNode f, Location l, Context c where diff --git a/python/ql/test/2/library-tests/PointsTo/metaclass/test.ql b/python/ql/test/2/library-tests/PointsTo/metaclass/test.ql index 68eec976105..0644e4cdf74 100644 --- a/python/ql/test/2/library-tests/PointsTo/metaclass/test.ql +++ b/python/ql/test/2/library-tests/PointsTo/metaclass/test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls where not cls.isC() diff --git a/python/ql/test/2/library-tests/classes/attr/class_attr.ql b/python/ql/test/2/library-tests/classes/attr/class_attr.ql index 197ab1a1e5e..1c9c5513a1d 100644 --- a/python/ql/test/2/library-tests/classes/attr/class_attr.ql +++ b/python/ql/test/2/library-tests/classes/attr/class_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name, Object obj where diff --git a/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql index be8272d1bd6..24724f4d859 100644 --- a/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql +++ b/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name where diff --git a/python/ql/test/2/library-tests/classes/attr/list_attr.ql b/python/ql/test/2/library-tests/classes/attr/list_attr.ql index c38694d5883..ad708711df4 100644 --- a/python/ql/test/2/library-tests/classes/attr/list_attr.ql +++ b/python/ql/test/2/library-tests/classes/attr/list_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, string name, Object what where diff --git a/python/ql/test/2/library-tests/classes/mro/mro.ql b/python/ql/test/2/library-tests/classes/mro/mro.ql index 0c4cf077adb..6a4d21921a1 100644 --- a/python/ql/test/2/library-tests/classes/mro/mro.ql +++ b/python/ql/test/2/library-tests/classes/mro/mro.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, ClassObject l, ClassObject r where diff --git a/python/ql/test/2/library-tests/modules/general/moduleobject_test.ql b/python/ql/test/2/library-tests/modules/general/moduleobject_test.ql index 50f79a57aed..27394e03096 100644 --- a/python/ql/test/2/library-tests/modules/general/moduleobject_test.ql +++ b/python/ql/test/2/library-tests/modules/general/moduleobject_test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where m.getName() = "package" or m.getName() = "confused_elements" diff --git a/python/ql/test/2/library-tests/modules/package_members/module_attributes.ql b/python/ql/test/2/library-tests/modules/package_members/module_attributes.ql index 6c16450f313..f7755b92e12 100644 --- a/python/ql/test/2/library-tests/modules/package_members/module_attributes.ql +++ b/python/ql/test/2/library-tests/modules/package_members/module_attributes.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() diff --git a/python/ql/test/2/library-tests/modules/package_members/module_exports.ql b/python/ql/test/2/library-tests/modules/package_members/module_exports.ql index bcfc0c60bfb..d04ef3bc9f3 100644 --- a/python/ql/test/2/library-tests/modules/package_members/module_exports.ql +++ b/python/ql/test/2/library-tests/modules/package_members/module_exports.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() and m.exports(name) diff --git a/python/ql/test/2/library-tests/modules/package_members/module_import_as.ql b/python/ql/test/2/library-tests/modules/package_members/module_import_as.ql index 50ded7b4124..97cc2e86665 100644 --- a/python/ql/test/2/library-tests/modules/package_members/module_import_as.ql +++ b/python/ql/test/2/library-tests/modules/package_members/module_import_as.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() and m.importedAs(name) diff --git a/python/ql/test/2/library-tests/modules/usage/ModuleUsage.ql b/python/ql/test/2/library-tests/modules/usage/ModuleUsage.ql index 5f776e2374e..0469f804ab3 100644 --- a/python/ql/test/2/library-tests/modules/usage/ModuleUsage.ql +++ b/python/ql/test/2/library-tests/modules/usage/ModuleUsage.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleValue mv, string usage where diff --git a/python/ql/test/2/library-tests/types/classes/mro_test.ql b/python/ql/test/2/library-tests/types/classes/mro_test.ql index fa2ac44d4d2..8d68b5b08fe 100644 --- a/python/ql/test/2/library-tests/types/classes/mro_test.ql +++ b/python/ql/test/2/library-tests/types/classes/mro_test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls where not cls.isC() diff --git a/python/ql/test/2/library-tests/types/classes/new_style.ql b/python/ql/test/2/library-tests/types/classes/new_style.ql index 2af40565329..fdd8fac80a8 100644 --- a/python/ql/test/2/library-tests/types/classes/new_style.ql +++ b/python/ql/test/2/library-tests/types/classes/new_style.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string style where diff --git a/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql b/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql index 415db290a05..5bf1ae1da00 100644 --- a/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql +++ b/python/ql/test/2/library-tests/types/exceptions/ExitRaises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r, Scope s, ClassObject cls where r.viableExceptionalExit_objectapi(s, cls) diff --git a/python/ql/test/2/library-tests/types/exceptions/Raises.ql b/python/ql/test/2/library-tests/types/exceptions/Raises.ql index 2415c707967..e4f9a6664d5 100644 --- a/python/ql/test/2/library-tests/types/exceptions/Raises.ql +++ b/python/ql/test/2/library-tests/types/exceptions/Raises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PyFunctionObject f, string type where diff --git a/python/ql/test/2/library-tests/types/functions/Calls.ql b/python/ql/test/2/library-tests/types/functions/Calls.ql index 6fc188753e5..5eaeb4559b0 100644 --- a/python/ql/test/2/library-tests/types/functions/Calls.ql +++ b/python/ql/test/2/library-tests/types/functions/Calls.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from FunctionObject func, ControlFlowNode call where func.getACall() = call diff --git a/python/ql/test/2/library-tests/types/functions/Never.ql b/python/ql/test/2/library-tests/types/functions/Never.ql index 1e43ead7dce..932121d058e 100644 --- a/python/ql/test/2/library-tests/types/functions/Never.ql +++ b/python/ql/test/2/library-tests/types/functions/Never.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from FunctionObject func where func.neverReturns() diff --git a/python/ql/test/2/library-tests/types/functions/ReturnTypes.ql b/python/ql/test/2/library-tests/types/functions/ReturnTypes.ql index beb955e1188..d35deea34bf 100644 --- a/python/ql/test/2/library-tests/types/functions/ReturnTypes.ql +++ b/python/ql/test/2/library-tests/types/functions/ReturnTypes.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PyFunctionObject func, ClassObject ret_type where func.getAnInferredReturnType() = ret_type diff --git a/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql b/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql index 24766db9f2e..9ab0b5e4bbd 100644 --- a/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql +++ b/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string name, BuiltinPropertyObject p where From 665104e62603a0dd7adf44b40bc6decd941dcded Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 23:08:11 +0000 Subject: [PATCH 07/22] Python: Fix Python 3 tests --- python/ql/test/3/extractor-tests/import_depth/test.ql | 1 + .../ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql | 1 + python/ql/test/3/library-tests/ControlFlow/Exceptions/Known.ql | 1 + python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql | 1 + .../ql/test/3/library-tests/ControlFlow/Exceptions/Unknown.ql | 1 + .../ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql | 2 +- python/ql/test/3/library-tests/PointsTo/inheritance/Calls.ql | 1 + python/ql/test/3/library-tests/PointsTo/metaclass/test.ql | 1 + .../PointsTo/regressions/subprocess-assert/ClassValue.ql | 1 + python/ql/test/3/library-tests/classes/attr/class_attr.ql | 1 + python/ql/test/3/library-tests/classes/attr/class_has_attr.ql | 1 + python/ql/test/3/library-tests/classes/meta/meta_obj.ql | 1 + python/ql/test/3/library-tests/classes/mro/mro.ql | 1 + python/ql/test/3/library-tests/classes/mro/mro_index.ql | 1 + .../test/3/library-tests/modules/general/moduleobject_test.ql | 1 + .../library-tests/modules/package_members/module_attributes.ql | 1 + .../3/library-tests/modules/package_members/module_exports.ql | 1 + .../3/library-tests/modules/package_members/module_import_as.ql | 1 + python/ql/test/3/library-tests/modules/usage/ModuleUsage.ql | 1 + python/ql/test/3/library-tests/types/classes/mro_test.ql | 1 + python/ql/test/3/library-tests/types/exceptions/Raises.ql | 1 + python/ql/test/3/library-tests/types/exceptions/Viable.ql | 1 + python/ql/test/3/library-tests/types/functions/Calls.ql | 1 + python/ql/test/3/library-tests/types/functions/Never.ql | 1 + python/ql/test/3/library-tests/types/functions/ReturnTypes.ql | 1 + python/ql/test/3/library-tests/types/namespaces/NameSpace.ql | 1 + .../test/3/library-tests/types/properties/BuiltinProperties.ql | 1 + 27 files changed, 27 insertions(+), 1 deletion(-) diff --git a/python/ql/test/3/extractor-tests/import_depth/test.ql b/python/ql/test/3/extractor-tests/import_depth/test.ql index ef626455fad..4f007e99468 100644 --- a/python/ql/test/3/extractor-tests/import_depth/test.ql +++ b/python/ql/test/3/extractor-tests/import_depth/test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m /* Exclude the builtins module as it has a different name under 2 and 3. */ diff --git a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql index 620944de5b9..60989ff8645 100644 --- a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql +++ b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ExceptFlowNode ex, Value val where ex.handledException(val, _, _) diff --git a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Known.ql b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Known.ql index 56498054f51..b773a172ee3 100644 --- a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Known.ql +++ b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Known.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r select r.getLocation().getStartLine(), r.toString(), r.getARaisedType().toString() diff --git a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql index f8e4a4b7dac..00cf5a7d2af 100644 --- a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql +++ b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ControlFlowNode r, ControlFlowNode s where diff --git a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Unknown.ql b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Unknown.ql index 29bad86bf0f..fe0fa6b0158 100644 --- a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Unknown.ql +++ b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Unknown.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r where r.raisesUnknownType() diff --git a/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql b/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql index 4299e11d660..242fb5bc781 100644 --- a/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql +++ b/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql @@ -1,5 +1,5 @@ import python -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo from ControlFlowNode f, Context c, boolean b where diff --git a/python/ql/test/3/library-tests/PointsTo/inheritance/Calls.ql b/python/ql/test/3/library-tests/PointsTo/inheritance/Calls.ql index f91d207fc70..3f111d6e08a 100644 --- a/python/ql/test/3/library-tests/PointsTo/inheritance/Calls.ql +++ b/python/ql/test/3/library-tests/PointsTo/inheritance/Calls.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Call c, FunctionObject f where f.getACall().getNode() = c diff --git a/python/ql/test/3/library-tests/PointsTo/metaclass/test.ql b/python/ql/test/3/library-tests/PointsTo/metaclass/test.ql index 68eec976105..0644e4cdf74 100644 --- a/python/ql/test/3/library-tests/PointsTo/metaclass/test.ql +++ b/python/ql/test/3/library-tests/PointsTo/metaclass/test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls where not cls.isC() diff --git a/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql b/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql index bc666b4f206..479ae6e5965 100644 --- a/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql +++ b/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo // as used in semmle.python.filters.Tests from ClassValue c, string base diff --git a/python/ql/test/3/library-tests/classes/attr/class_attr.ql b/python/ql/test/3/library-tests/classes/attr/class_attr.ql index 197ab1a1e5e..1c9c5513a1d 100644 --- a/python/ql/test/3/library-tests/classes/attr/class_attr.ql +++ b/python/ql/test/3/library-tests/classes/attr/class_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name, Object obj where diff --git a/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql index be8272d1bd6..24724f4d859 100644 --- a/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql +++ b/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name where diff --git a/python/ql/test/3/library-tests/classes/meta/meta_obj.ql b/python/ql/test/3/library-tests/classes/meta/meta_obj.ql index e85127a9305..af46400ce00 100644 --- a/python/ql/test/3/library-tests/classes/meta/meta_obj.ql +++ b/python/ql/test/3/library-tests/classes/meta/meta_obj.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls where not cls.isC() diff --git a/python/ql/test/3/library-tests/classes/mro/mro.ql b/python/ql/test/3/library-tests/classes/mro/mro.ql index 576d6a75afd..86934f52c11 100644 --- a/python/ql/test/3/library-tests/classes/mro/mro.ql +++ b/python/ql/test/3/library-tests/classes/mro/mro.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, ClassObject l, ClassObject r where diff --git a/python/ql/test/3/library-tests/classes/mro/mro_index.ql b/python/ql/test/3/library-tests/classes/mro/mro_index.ql index da40776044e..6a65d27b716 100644 --- a/python/ql/test/3/library-tests/classes/mro/mro_index.ql +++ b/python/ql/test/3/library-tests/classes/mro/mro_index.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, ClassObject sup, int index where diff --git a/python/ql/test/3/library-tests/modules/general/moduleobject_test.ql b/python/ql/test/3/library-tests/modules/general/moduleobject_test.ql index a3a1ac6b185..db5b72e4dc4 100644 --- a/python/ql/test/3/library-tests/modules/general/moduleobject_test.ql +++ b/python/ql/test/3/library-tests/modules/general/moduleobject_test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() and not m.getName() = "__future__" diff --git a/python/ql/test/3/library-tests/modules/package_members/module_attributes.ql b/python/ql/test/3/library-tests/modules/package_members/module_attributes.ql index 6c16450f313..f7755b92e12 100644 --- a/python/ql/test/3/library-tests/modules/package_members/module_attributes.ql +++ b/python/ql/test/3/library-tests/modules/package_members/module_attributes.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() diff --git a/python/ql/test/3/library-tests/modules/package_members/module_exports.ql b/python/ql/test/3/library-tests/modules/package_members/module_exports.ql index bcfc0c60bfb..d04ef3bc9f3 100644 --- a/python/ql/test/3/library-tests/modules/package_members/module_exports.ql +++ b/python/ql/test/3/library-tests/modules/package_members/module_exports.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() and m.exports(name) diff --git a/python/ql/test/3/library-tests/modules/package_members/module_import_as.ql b/python/ql/test/3/library-tests/modules/package_members/module_import_as.ql index 50ded7b4124..97cc2e86665 100644 --- a/python/ql/test/3/library-tests/modules/package_members/module_import_as.ql +++ b/python/ql/test/3/library-tests/modules/package_members/module_import_as.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleObject m, string name where not m.isC() and m.importedAs(name) diff --git a/python/ql/test/3/library-tests/modules/usage/ModuleUsage.ql b/python/ql/test/3/library-tests/modules/usage/ModuleUsage.ql index 5f776e2374e..0469f804ab3 100644 --- a/python/ql/test/3/library-tests/modules/usage/ModuleUsage.ql +++ b/python/ql/test/3/library-tests/modules/usage/ModuleUsage.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleValue mv, string usage where diff --git a/python/ql/test/3/library-tests/types/classes/mro_test.ql b/python/ql/test/3/library-tests/types/classes/mro_test.ql index 04b65ae2bef..4dc9bc153a2 100644 --- a/python/ql/test/3/library-tests/types/classes/mro_test.ql +++ b/python/ql/test/3/library-tests/types/classes/mro_test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, ClassObject sup where not cls.isC() diff --git a/python/ql/test/3/library-tests/types/exceptions/Raises.ql b/python/ql/test/3/library-tests/types/exceptions/Raises.ql index 2415c707967..e4f9a6664d5 100644 --- a/python/ql/test/3/library-tests/types/exceptions/Raises.ql +++ b/python/ql/test/3/library-tests/types/exceptions/Raises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PyFunctionObject f, string type where diff --git a/python/ql/test/3/library-tests/types/exceptions/Viable.ql b/python/ql/test/3/library-tests/types/exceptions/Viable.ql index bf00a0675d6..589e2630bb9 100644 --- a/python/ql/test/3/library-tests/types/exceptions/Viable.ql +++ b/python/ql/test/3/library-tests/types/exceptions/Viable.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r, ControlFlowNode n, ClassObject ex where r.viableExceptionEdge_objectapi(n, ex) diff --git a/python/ql/test/3/library-tests/types/functions/Calls.ql b/python/ql/test/3/library-tests/types/functions/Calls.ql index 6fc188753e5..5eaeb4559b0 100644 --- a/python/ql/test/3/library-tests/types/functions/Calls.ql +++ b/python/ql/test/3/library-tests/types/functions/Calls.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from FunctionObject func, ControlFlowNode call where func.getACall() = call diff --git a/python/ql/test/3/library-tests/types/functions/Never.ql b/python/ql/test/3/library-tests/types/functions/Never.ql index 1e43ead7dce..932121d058e 100644 --- a/python/ql/test/3/library-tests/types/functions/Never.ql +++ b/python/ql/test/3/library-tests/types/functions/Never.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from FunctionObject func where func.neverReturns() diff --git a/python/ql/test/3/library-tests/types/functions/ReturnTypes.ql b/python/ql/test/3/library-tests/types/functions/ReturnTypes.ql index beb955e1188..d35deea34bf 100644 --- a/python/ql/test/3/library-tests/types/functions/ReturnTypes.ql +++ b/python/ql/test/3/library-tests/types/functions/ReturnTypes.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PyFunctionObject func, ClassObject ret_type where func.getAnInferredReturnType() = ret_type diff --git a/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql b/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql index 38241e8fabc..f41d977d47b 100644 --- a/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql +++ b/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql @@ -6,6 +6,7 @@ */ import python +private import LegacyPointsTo from Scope s, string name, Object val where diff --git a/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql b/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql index 24766db9f2e..9ab0b5e4bbd 100644 --- a/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql +++ b/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string name, BuiltinPropertyObject p where From b3b87c968bb1582f09dd4913a9e90d22ab15755b Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 23:08:43 +0000 Subject: [PATCH 08/22] Python: Fix extractor/experimental tests --- .../experimental/library-tests/CallGraph/InlineCallGraphTest.ql | 1 + python/ql/test/extractor-tests/double-import/ModuleNames.ql | 1 + python/ql/test/extractor-tests/unicode_decoding/test.ql | 1 + 3 files changed, 3 insertions(+) diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index 1771727dbbc..5cdbd9e6a4e 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -1,6 +1,7 @@ import python import utils.test.InlineExpectationsTest private import semmle.python.dataflow.new.internal.DataFlowDispatch as TT +private import LegacyPointsTo /** Holds when `call` is resolved to `callable` using points-to based call-graph. */ predicate pointsToCallEdge(CallNode call, Function callable) { diff --git a/python/ql/test/extractor-tests/double-import/ModuleNames.ql b/python/ql/test/extractor-tests/double-import/ModuleNames.ql index 54aa78e23a3..6d25cf91f70 100644 --- a/python/ql/test/extractor-tests/double-import/ModuleNames.ql +++ b/python/ql/test/extractor-tests/double-import/ModuleNames.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Container path, string name where exists(ModuleValue m | m.getPath() = path and m.getName() = name) diff --git a/python/ql/test/extractor-tests/unicode_decoding/test.ql b/python/ql/test/extractor-tests/unicode_decoding/test.ql index b2d51b10d22..4e0937a07c4 100644 --- a/python/ql/test/extractor-tests/unicode_decoding/test.ql +++ b/python/ql/test/extractor-tests/unicode_decoding/test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Object o, string s where From 7176898503e02e0bedcc8fd1497e4ca97a256625 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 30 Oct 2025 23:10:15 +0000 Subject: [PATCH 09/22] Python: Fix library tests --- python/ql/test/library-tests/PointsTo/api/ClassValue.ql | 1 + python/ql/test/library-tests/PointsTo/api/Constants.ql | 1 + python/ql/test/library-tests/PointsTo/api/QualifedNames.ql | 1 + python/ql/test/library-tests/PointsTo/api/Value.ql | 1 + python/ql/test/library-tests/PointsTo/calls/GetACall.ql | 1 + .../test/library-tests/PointsTo/calls/getArgumentForCall.ql | 1 + .../library-tests/PointsTo/calls/getNamedArgumentForCall.ql | 1 + python/ql/test/library-tests/PointsTo/calls/getParameter.ql | 1 + .../test/library-tests/PointsTo/calls/getParameterByName.ql | 1 + python/ql/test/library-tests/PointsTo/decorators/Values.ql | 3 +-- python/ql/test/library-tests/PointsTo/functions/Calls.ql | 1 + .../ql/test/library-tests/PointsTo/functions/NeverReturns.ql | 1 + python/ql/test/library-tests/PointsTo/functions/test.ql | 1 + python/ql/test/library-tests/PointsTo/general/Util.qll | 1 + python/ql/test/library-tests/PointsTo/global/Global.ql | 4 +--- .../ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql | 1 + python/ql/test/library-tests/PointsTo/inheritance/Calls.ql | 1 + python/ql/test/library-tests/PointsTo/inheritance/Declares.ql | 1 + .../ql/test/library-tests/PointsTo/inheritance/MetaClass.ql | 1 + .../ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql | 1 + python/ql/test/library-tests/PointsTo/metaclass/Failed.ql | 1 + python/ql/test/library-tests/PointsTo/metaclass/Style.ql | 1 + python/ql/test/library-tests/PointsTo/metaclass/test.ql | 2 +- python/ql/test/library-tests/PointsTo/new/Call.ql | 1 + python/ql/test/library-tests/PointsTo/new/ClassMethod.ql | 1 + python/ql/test/library-tests/PointsTo/new/NameSpace.ql | 1 + python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql | 2 +- python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql | 2 +- .../ql/test/library-tests/PointsTo/new/PointsToWithContext.ql | 3 +-- python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql | 2 +- python/ql/test/library-tests/PointsTo/new/Reachable.ql | 2 +- python/ql/test/library-tests/PointsTo/new/SSA.ql | 3 +-- .../test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql | 1 - .../test/library-tests/PointsTo/new/SourceNodeDefinitions.ql | 1 - python/ql/test/library-tests/PointsTo/new/SsaAttr.ql | 3 +-- python/ql/test/library-tests/PointsTo/new/SsaUses.ql | 1 - python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql | 3 +-- python/ql/test/library-tests/PointsTo/new/Util.qll | 2 +- python/ql/test/library-tests/PointsTo/new/VarUses.ql | 2 +- .../PointsTo/regressions/missing/metaclass/getACall.ql | 1 + .../module-imports/conflict-stdlib/LocalModuleWithRef.ql | 1 + .../module-imports/conflict-stdlib/ModuleWithLocalRef.ql | 1 + python/ql/test/library-tests/PointsTo/returns/Test.ql | 1 + python/ql/test/library-tests/PointsTo/subclass/Checks.ql | 2 +- python/ql/test/library-tests/attributes/SelfAttribute.ql | 1 + python/ql/test/library-tests/classes/abstract/Abstract.ql | 1 + python/ql/test/library-tests/classes/attr/class_attr.ql | 1 + .../ql/test/library-tests/classes/attr/class_defined_attr.ql | 1 + .../ql/test/library-tests/classes/attr/class_defines_attr.ql | 1 + python/ql/test/library-tests/classes/attr/class_has_attr.ql | 1 + python/ql/test/library-tests/classes/attr/hash.ql | 1 + python/ql/test/library-tests/classes/mro/C3.ql | 1 + python/ql/test/library-tests/dependencies/Dependencies.ql | 1 + python/ql/test/library-tests/descriptors/Descriptors.ql | 1 + python/ql/test/library-tests/descriptors/Methods.ql | 1 + python/ql/test/library-tests/descriptors/Properties.ql | 1 + python/ql/test/library-tests/exceptions/Handles.ql | 1 + python/ql/test/library-tests/exceptions/Legal.ql | 1 + .../ql/test/library-tests/modules/duplicate_name/Modules.ql | 1 + python/ql/test/library-tests/objects/Name.ql | 1 + python/ql/test/library-tests/overrides/FunctionOverrides.ql | 1 + python/ql/test/library-tests/state_tracking/Test.ql | 1 + python/ql/test/library-tests/taint/config/TaintLib.qll | 1 + python/ql/test/library-tests/taint/config/TaintedArgument.ql | 1 + python/ql/test/library-tests/taint/general/ModuleAttribute.ql | 1 + python/ql/test/library-tests/taint/general/TaintLib.qll | 1 + python/ql/test/library-tests/types/attributes/Test.ql | 1 + .../ql/test/library-tests/types/classattr/ClassAttribute.ql | 1 + python/ql/test/library-tests/types/classattr/ClassMember.ql | 1 + .../ql/test/library-tests/types/classattr/SpecialAttribute.ql | 1 + python/ql/test/library-tests/types/classes/FailedInference.ql | 2 +- python/ql/test/library-tests/types/classes/duplicate_base.ql | 1 + python/ql/test/library-tests/types/exceptions/ExitRaises.ql | 1 + python/ql/test/library-tests/types/exceptions/Handles.ql | 1 + python/ql/test/library-tests/types/exceptions/Impossible.ql | 1 + python/ql/test/library-tests/types/exceptions/LineRaises.ql | 1 + python/ql/test/library-tests/types/exceptions/Raises.ql | 1 + python/ql/test/library-tests/types/exceptions/Reraises.ql | 1 + python/ql/test/library-tests/types/exceptions/Viable.ql | 1 + python/ql/test/library-tests/types/properties/Deleters.ql | 1 + python/ql/test/library-tests/types/properties/Getters.ql | 1 + .../test/library-tests/types/properties/PythonProperties.ql | 1 + python/ql/test/library-tests/types/properties/Setters.ql | 1 + 83 files changed, 80 insertions(+), 25 deletions(-) diff --git a/python/ql/test/library-tests/PointsTo/api/ClassValue.ql b/python/ql/test/library-tests/PointsTo/api/ClassValue.ql index 230cc487ea4..65a4c73d4a6 100644 --- a/python/ql/test/library-tests/PointsTo/api/ClassValue.ql +++ b/python/ql/test/library-tests/PointsTo/api/ClassValue.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassValue cls, string description where diff --git a/python/ql/test/library-tests/PointsTo/api/Constants.ql b/python/ql/test/library-tests/PointsTo/api/Constants.ql index 151f6b9ce9c..a6072a1d8e8 100644 --- a/python/ql/test/library-tests/PointsTo/api/Constants.ql +++ b/python/ql/test/library-tests/PointsTo/api/Constants.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from string txt, Value val where diff --git a/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql b/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql index daafad0492b..c756265295b 100644 --- a/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql +++ b/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from FunctionValue v, string name where diff --git a/python/ql/test/library-tests/PointsTo/api/Value.ql b/python/ql/test/library-tests/PointsTo/api/Value.ql index 9c6e0739461..fadf008f6ea 100644 --- a/python/ql/test/library-tests/PointsTo/api/Value.ql +++ b/python/ql/test/library-tests/PointsTo/api/Value.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Value val, string name where diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql index 84f2ab4fb4a..8c6cc76c031 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ControlFlowNode call, Value func where call = func.getACall() diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql index 7c76b9e0ce5..d388f96783c 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from CallNode call, CallableValue callable, int i select call.getLocation().getStartLine(), call.toString(), callable.toString(), i, diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql index 4cb3fbdf335..7fa39194deb 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from CallNode call, CallableValue callable, string name select call.getLocation().getStartLine(), call.toString(), callable.toString(), name, diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.ql b/python/ql/test/library-tests/PointsTo/calls/getParameter.ql index 07f12cce36f..1cabfeb45bc 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameter.ql +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from CallableValue callable, int i select callable.toString(), i, callable.getParameter(i).toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql index d4766b680f7..20c4c77f121 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from CallableValue callable, string name select callable.toString(), name, callable.getParameterByName(name).toString() diff --git a/python/ql/test/library-tests/PointsTo/decorators/Values.ql b/python/ql/test/library-tests/PointsTo/decorators/Values.ql index fc7a08db20b..fe4b6d080f4 100644 --- a/python/ql/test/library-tests/PointsTo/decorators/Values.ql +++ b/python/ql/test/library-tests/PointsTo/decorators/Values.ql @@ -1,6 +1,5 @@ import python -import semmle.python.pointsto.PointsTo -import semmle.python.objects.ObjectInternal +private import LegacyPointsTo from NameNode f, Context ctx, ObjectInternal v where diff --git a/python/ql/test/library-tests/PointsTo/functions/Calls.ql b/python/ql/test/library-tests/PointsTo/functions/Calls.ql index 5bc29b5aaf3..659ba4143f6 100644 --- a/python/ql/test/library-tests/PointsTo/functions/Calls.ql +++ b/python/ql/test/library-tests/PointsTo/functions/Calls.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from CallNode call, FunctionObject func, string kind where diff --git a/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql b/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql index c576651a8e6..0a20f8e1b1f 100644 --- a/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql +++ b/python/ql/test/library-tests/PointsTo/functions/NeverReturns.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from FunctionObject f where f.neverReturns() diff --git a/python/ql/test/library-tests/PointsTo/functions/test.ql b/python/ql/test/library-tests/PointsTo/functions/test.ql index f85e95f5fe4..01f8416c8dc 100644 --- a/python/ql/test/library-tests/PointsTo/functions/test.ql +++ b/python/ql/test/library-tests/PointsTo/functions/test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Call c, FunctionObject f where diff --git a/python/ql/test/library-tests/PointsTo/general/Util.qll b/python/ql/test/library-tests/PointsTo/general/Util.qll index 1c26d7d830b..289e71a9e6c 100644 --- a/python/ql/test/library-tests/PointsTo/general/Util.qll +++ b/python/ql/test/library-tests/PointsTo/general/Util.qll @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo string repr(Object o) { not o instanceof StringObject and not o = theBoundMethodType() and result = o.toString() diff --git a/python/ql/test/library-tests/PointsTo/global/Global.ql b/python/ql/test/library-tests/PointsTo/global/Global.ql index f9f52b12641..4dc6d16d379 100644 --- a/python/ql/test/library-tests/PointsTo/global/Global.ql +++ b/python/ql/test/library-tests/PointsTo/global/Global.ql @@ -1,7 +1,5 @@ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext -import semmle.python.objects.ObjectInternal +private import LegacyPointsTo from ControlFlowNode f, PointsToContext ctx, Value obj, ControlFlowNode orig where diff --git a/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql index f1201eba0dc..01f69d8bb12 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, ClassObject base, int n where diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql b/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql index f91d207fc70..3f111d6e08a 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/Calls.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Call c, FunctionObject f where f.getACall().getNode() = c diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql b/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql index a2c762be860..2fe61ca2d7f 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/Declares.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string name where class_declares_attribute(cls, name) diff --git a/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql index 0ca90782119..a487c16e953 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, ClassObject meta where diff --git a/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql index 338ea118ac1..c3156eb1fa0 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, ClassObject sup where diff --git a/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql b/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql index a5d2afd4241..4129c99666b 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string reason where diff --git a/python/ql/test/library-tests/PointsTo/metaclass/Style.ql b/python/ql/test/library-tests/PointsTo/metaclass/Style.ql index f29ba3a8b7c..7ab5b4a329f 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/Style.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/Style.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string style where diff --git a/python/ql/test/library-tests/PointsTo/metaclass/test.ql b/python/ql/test/library-tests/PointsTo/metaclass/test.ql index d08f4e37fa6..471c01599d6 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/test.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/test.ql @@ -1,5 +1,5 @@ import python -private import semmle.python.objects.ObjectInternal +private import LegacyPointsTo /** An unknown type. Not usually visible. */ class UnknownType extends UnknownClassInternal { diff --git a/python/ql/test/library-tests/PointsTo/new/Call.ql b/python/ql/test/library-tests/PointsTo/new/Call.ql index f014001f315..e924398ca40 100644 --- a/python/ql/test/library-tests/PointsTo/new/Call.ql +++ b/python/ql/test/library-tests/PointsTo/new/Call.ql @@ -1,5 +1,6 @@ import python import Util +private import LegacyPointsTo from ControlFlowNode call, FunctionObject func where call = func.getACall() diff --git a/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql b/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql index 17f73420e05..9eac6e3fea2 100644 --- a/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql +++ b/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql @@ -1,5 +1,6 @@ import python import Util +private import LegacyPointsTo from ClassMethodObject cm, CallNode call where call = cm.getACall() diff --git a/python/ql/test/library-tests/PointsTo/new/NameSpace.ql b/python/ql/test/library-tests/PointsTo/new/NameSpace.ql index 5d099f78b61..6150b94aee1 100644 --- a/python/ql/test/library-tests/PointsTo/new/NameSpace.ql +++ b/python/ql/test/library-tests/PointsTo/new/NameSpace.ql @@ -1,5 +1,6 @@ import python import Util +private import LegacyPointsTo from Scope s, string name, Object val where diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql b/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql index 9e744591df2..271f35db996 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql @@ -1,6 +1,6 @@ import python import Util -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo /* This test should return _no_ results. */ predicate relevant_node(ControlFlowNode n) { diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql index cb91e18dafe..2526819b76a 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToUnknown.ql @@ -1,6 +1,6 @@ import python import Util -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo from ControlFlowNode f, ControlFlowNode x where PointsTo::pointsTo(f, _, ObjectInternal::unknown(), x) diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql index dbed1a9a7f6..bad7589d0a2 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql @@ -1,7 +1,6 @@ import python import Util -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x, PointsToContext ctx where PointsTo::points_to(f, ctx, o, c, x) diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql index 5747ce18fd5..20a23abced7 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql @@ -1,6 +1,6 @@ import python import Util -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x where PointsTo::points_to(f, _, o, c, x) diff --git a/python/ql/test/library-tests/PointsTo/new/Reachable.ql b/python/ql/test/library-tests/PointsTo/new/Reachable.ql index f8b2f0585eb..2376f13c752 100644 --- a/python/ql/test/library-tests/PointsTo/new/Reachable.ql +++ b/python/ql/test/library-tests/PointsTo/new/Reachable.ql @@ -1,5 +1,5 @@ import python -private import semmle.python.pointsto.PointsTo +private import LegacyPointsTo import Util from ControlFlowNode f, Context ctx diff --git a/python/ql/test/library-tests/PointsTo/new/SSA.ql b/python/ql/test/library-tests/PointsTo/new/SSA.ql index 7b41f3c427e..c919e1d4856 100644 --- a/python/ql/test/library-tests/PointsTo/new/SSA.ql +++ b/python/ql/test/library-tests/PointsTo/new/SSA.ql @@ -1,6 +1,5 @@ import python -private import semmle.python.pointsto.PointsTo -private import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo import Util predicate ssa_variable_points_to( diff --git a/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql index 8cf0b4c15a6..117afe8100e 100644 --- a/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql +++ b/python/ql/test/library-tests/PointsTo/new/SourceEdgeDefinitions.ql @@ -1,5 +1,4 @@ import python -import semmle.python.pointsto.PointsTo import Util from SsaSourceVariable var, ControlFlowNode use, BasicBlock pred diff --git a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql index 77f6ab0923b..2c5867f9c4f 100644 --- a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql +++ b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql @@ -1,5 +1,4 @@ import python -import semmle.python.pointsto.PointsTo import Util from SsaSourceVariable var, ControlFlowNode defn, string kind diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql index 67d85c2e3bd..c9b136f0c02 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql @@ -1,6 +1,5 @@ import python -private import semmle.python.pointsto.PointsTo -private import semmle.python.objects.ObjectInternal +private import LegacyPointsTo import Util from EssaVariable var, string name, ObjectInternal o, Context ctx diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql index 2a8e8f1e750..9a250b6610f 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql @@ -1,5 +1,4 @@ import python -import semmle.python.pointsto.PointsTo import Util from EssaVariable var, ControlFlowNode use diff --git a/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql index d473e4e804a..1132f04df07 100644 --- a/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql +++ b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql @@ -1,6 +1,5 @@ import python -import semmle.python.pointsto.PointsTo -import semmle.python.pointsto.PointsToContext +private import LegacyPointsTo import Util from diff --git a/python/ql/test/library-tests/PointsTo/new/Util.qll b/python/ql/test/library-tests/PointsTo/new/Util.qll index b83ad89d1c8..23c5aa8df7c 100644 --- a/python/ql/test/library-tests/PointsTo/new/Util.qll +++ b/python/ql/test/library-tests/PointsTo/new/Util.qll @@ -1,5 +1,5 @@ import python -import semmle.python.objects.ObjectInternal +private import LegacyPointsTo bindingset[which] string locate(Location l, string which) { diff --git a/python/ql/test/library-tests/PointsTo/new/VarUses.ql b/python/ql/test/library-tests/PointsTo/new/VarUses.ql index 58de54d7a3d..50b07d03be0 100644 --- a/python/ql/test/library-tests/PointsTo/new/VarUses.ql +++ b/python/ql/test/library-tests/PointsTo/new/VarUses.ql @@ -1,5 +1,5 @@ import python -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo import Util from SsaSourceVariable var, ControlFlowNode use diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql index e555c927d6a..5ca3c9518d6 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PythonFunctionValue func select func, func.getACall() diff --git a/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/LocalModuleWithRef.ql b/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/LocalModuleWithRef.ql index 5bdb99415b2..f6bc97bf1f0 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/LocalModuleWithRef.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/LocalModuleWithRef.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleValue mv, ControlFlowNode ref, string local_external where diff --git a/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/ModuleWithLocalRef.ql b/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/ModuleWithLocalRef.ql index 030211ba0bf..1422d5731fd 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/ModuleWithLocalRef.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/wrong/module-imports/conflict-stdlib/ModuleWithLocalRef.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ModuleValue mv, ControlFlowNode ref, string in_stdlib, string local_external, string is_missing where diff --git a/python/ql/test/library-tests/PointsTo/returns/Test.ql b/python/ql/test/library-tests/PointsTo/returns/Test.ql index 8546de90f24..928e4c9672f 100644 --- a/python/ql/test/library-tests/PointsTo/returns/Test.ql +++ b/python/ql/test/library-tests/PointsTo/returns/Test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PyFunctionObject f select f.toString(), f.getAnInferredReturnType().toString() diff --git a/python/ql/test/library-tests/PointsTo/subclass/Checks.ql b/python/ql/test/library-tests/PointsTo/subclass/Checks.ql index a82002b1d5f..f9deaabbc88 100644 --- a/python/ql/test/library-tests/PointsTo/subclass/Checks.ql +++ b/python/ql/test/library-tests/PointsTo/subclass/Checks.ql @@ -1,5 +1,5 @@ import python -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo from Value sup, Value cls where Expressions::requireSubClass(cls, sup) diff --git a/python/ql/test/library-tests/attributes/SelfAttribute.ql b/python/ql/test/library-tests/attributes/SelfAttribute.ql index 66993121241..79ceff3a08a 100644 --- a/python/ql/test/library-tests/attributes/SelfAttribute.ql +++ b/python/ql/test/library-tests/attributes/SelfAttribute.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from SelfAttributeRead sa, int line, string g, string l where diff --git a/python/ql/test/library-tests/classes/abstract/Abstract.ql b/python/ql/test/library-tests/classes/abstract/Abstract.ql index bd2f98034cb..02c76421126 100644 --- a/python/ql/test/library-tests/classes/abstract/Abstract.ql +++ b/python/ql/test/library-tests/classes/abstract/Abstract.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string abstract where diff --git a/python/ql/test/library-tests/classes/attr/class_attr.ql b/python/ql/test/library-tests/classes/attr/class_attr.ql index 197ab1a1e5e..1c9c5513a1d 100644 --- a/python/ql/test/library-tests/classes/attr/class_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name, Object obj where diff --git a/python/ql/test/library-tests/classes/attr/class_defined_attr.ql b/python/ql/test/library-tests/classes/attr/class_defined_attr.ql index d7583e689c4..4fc6f7b67d2 100644 --- a/python/ql/test/library-tests/classes/attr/class_defined_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_defined_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name, Object obj where diff --git a/python/ql/test/library-tests/classes/attr/class_defines_attr.ql b/python/ql/test/library-tests/classes/attr/class_defines_attr.ql index 6b266a0d40f..71dee836a9f 100644 --- a/python/ql/test/library-tests/classes/attr/class_defines_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_defines_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name where diff --git a/python/ql/test/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/library-tests/classes/attr/class_has_attr.ql index be8272d1bd6..24724f4d859 100644 --- a/python/ql/test/library-tests/classes/attr/class_has_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_has_attr.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, string name where diff --git a/python/ql/test/library-tests/classes/attr/hash.ql b/python/ql/test/library-tests/classes/attr/hash.ql index 19ac8933f69..3708e62ccdd 100644 --- a/python/ql/test/library-tests/classes/attr/hash.ql +++ b/python/ql/test/library-tests/classes/attr/hash.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, int line, Object obj where diff --git a/python/ql/test/library-tests/classes/mro/C3.ql b/python/ql/test/library-tests/classes/mro/C3.ql index 981a55893c2..60b4b0c1e1b 100644 --- a/python/ql/test/library-tests/classes/mro/C3.ql +++ b/python/ql/test/library-tests/classes/mro/C3.ql @@ -1,5 +1,6 @@ import python import semmle.python.pointsto.MRO +private import LegacyPointsTo from ClassValue cls where not cls.isBuiltin() diff --git a/python/ql/test/library-tests/dependencies/Dependencies.ql b/python/ql/test/library-tests/dependencies/Dependencies.ql index 12378a567d2..6f0f6cb3bb7 100644 --- a/python/ql/test/library-tests/dependencies/Dependencies.ql +++ b/python/ql/test/library-tests/dependencies/Dependencies.ql @@ -1,5 +1,6 @@ import python import semmle.python.dependencies.Dependencies +private import LegacyPointsTo from DependencyKind dk, AstNode src, Object target where dk.isADependency(src, target) diff --git a/python/ql/test/library-tests/descriptors/Descriptors.ql b/python/ql/test/library-tests/descriptors/Descriptors.ql index e577d47b421..7a0f196f3f6 100644 --- a/python/ql/test/library-tests/descriptors/Descriptors.ql +++ b/python/ql/test/library-tests/descriptors/Descriptors.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string kind where diff --git a/python/ql/test/library-tests/descriptors/Methods.ql b/python/ql/test/library-tests/descriptors/Methods.ql index 3761ec5f7b5..49c8a3bbbff 100644 --- a/python/ql/test/library-tests/descriptors/Methods.ql +++ b/python/ql/test/library-tests/descriptors/Methods.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo int lineof(Object o) { result = o.getOrigin().getLocation().getStartLine() } diff --git a/python/ql/test/library-tests/descriptors/Properties.ql b/python/ql/test/library-tests/descriptors/Properties.ql index 29f9e2577a0..349d0a242f9 100644 --- a/python/ql/test/library-tests/descriptors/Properties.ql +++ b/python/ql/test/library-tests/descriptors/Properties.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PropertyValue p, string method_name, FunctionValue method where diff --git a/python/ql/test/library-tests/exceptions/Handles.ql b/python/ql/test/library-tests/exceptions/Handles.ql index 620944de5b9..60989ff8645 100644 --- a/python/ql/test/library-tests/exceptions/Handles.ql +++ b/python/ql/test/library-tests/exceptions/Handles.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ExceptFlowNode ex, Value val where ex.handledException(val, _, _) diff --git a/python/ql/test/library-tests/exceptions/Legal.ql b/python/ql/test/library-tests/exceptions/Legal.ql index bfe47717d23..5b10854c1e1 100644 --- a/python/ql/test/library-tests/exceptions/Legal.ql +++ b/python/ql/test/library-tests/exceptions/Legal.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string legal where diff --git a/python/ql/test/library-tests/modules/duplicate_name/Modules.ql b/python/ql/test/library-tests/modules/duplicate_name/Modules.ql index a6477c7d6af..af3df6f6eca 100644 --- a/python/ql/test/library-tests/modules/duplicate_name/Modules.ql +++ b/python/ql/test/library-tests/modules/duplicate_name/Modules.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from string name, int mcnt where mcnt = strictcount(Module m | m.getName() = name) and mcnt > 1 diff --git a/python/ql/test/library-tests/objects/Name.ql b/python/ql/test/library-tests/objects/Name.ql index c274ed34554..e4bac8bba65 100644 --- a/python/ql/test/library-tests/objects/Name.ql +++ b/python/ql/test/library-tests/objects/Name.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from Object o, string name where diff --git a/python/ql/test/library-tests/overrides/FunctionOverrides.ql b/python/ql/test/library-tests/overrides/FunctionOverrides.ql index c719006665d..a30ca89d6cc 100644 --- a/python/ql/test/library-tests/overrides/FunctionOverrides.ql +++ b/python/ql/test/library-tests/overrides/FunctionOverrides.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PythonFunctionValue f, string overriding, string overridden where diff --git a/python/ql/test/library-tests/state_tracking/Test.ql b/python/ql/test/library-tests/state_tracking/Test.ql index a0a12e8615d..706dc73191a 100644 --- a/python/ql/test/library-tests/state_tracking/Test.ql +++ b/python/ql/test/library-tests/state_tracking/Test.ql @@ -1,5 +1,6 @@ import python import Lib +private import LegacyPointsTo from ControlFlowNode f, TrackableState state, Context ctx, boolean sense where diff --git a/python/ql/test/library-tests/taint/config/TaintLib.qll b/python/ql/test/library-tests/taint/config/TaintLib.qll index 35eebe8ffa6..82bc4afa72e 100644 --- a/python/ql/test/library-tests/taint/config/TaintLib.qll +++ b/python/ql/test/library-tests/taint/config/TaintLib.qll @@ -1,5 +1,6 @@ import python import semmle.python.dataflow.TaintTracking +private import LegacyPointsTo class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/config/TaintedArgument.ql b/python/ql/test/library-tests/taint/config/TaintedArgument.ql index b8753b3fe00..e3689bca0d8 100644 --- a/python/ql/test/library-tests/taint/config/TaintedArgument.ql +++ b/python/ql/test/library-tests/taint/config/TaintedArgument.ql @@ -2,6 +2,7 @@ import python import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.dataflow.Implementation +private import LegacyPointsTo from TaintTrackingImplementation config, TaintTrackingNode src, CallNode call, diff --git a/python/ql/test/library-tests/taint/general/ModuleAttribute.ql b/python/ql/test/library-tests/taint/general/ModuleAttribute.ql index 6a4349b4100..8da8cb5048e 100644 --- a/python/ql/test/library-tests/taint/general/ModuleAttribute.ql +++ b/python/ql/test/library-tests/taint/general/ModuleAttribute.ql @@ -1,6 +1,7 @@ import python import semmle.python.dataflow.Implementation import TaintLib +private import LegacyPointsTo from ModuleValue m, string name, TaintedNode origin, TaintTrackingImplementation impl where impl.moduleAttributeTainted(m, name, origin) diff --git a/python/ql/test/library-tests/taint/general/TaintLib.qll b/python/ql/test/library-tests/taint/general/TaintLib.qll index af3799c3b95..eb55093ad09 100644 --- a/python/ql/test/library-tests/taint/general/TaintLib.qll +++ b/python/ql/test/library-tests/taint/general/TaintLib.qll @@ -1,5 +1,6 @@ import python import semmle.python.dataflow.TaintTracking +private import LegacyPointsTo class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/types/attributes/Test.ql b/python/ql/test/library-tests/types/attributes/Test.ql index 9e066a6414b..ba2e8995dc2 100644 --- a/python/ql/test/library-tests/types/attributes/Test.ql +++ b/python/ql/test/library-tests/types/attributes/Test.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, ClassObject start, string name, Object val where not name.substring(0, 2) = "__" and val = cls.lookupMro(start, name) diff --git a/python/ql/test/library-tests/types/classattr/ClassAttribute.ql b/python/ql/test/library-tests/types/classattr/ClassAttribute.ql index d0633a36e3a..fc775ebf39b 100644 --- a/python/ql/test/library-tests/types/classattr/ClassAttribute.ql +++ b/python/ql/test/library-tests/types/classattr/ClassAttribute.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, string name, string kind where diff --git a/python/ql/test/library-tests/types/classattr/ClassMember.ql b/python/ql/test/library-tests/types/classattr/ClassMember.ql index d1e136a5108..54f1d1a5b02 100644 --- a/python/ql/test/library-tests/types/classattr/ClassMember.ql +++ b/python/ql/test/library-tests/types/classattr/ClassMember.ql @@ -5,6 +5,7 @@ */ import python +private import LegacyPointsTo from ClassObject cls, string name, string kind, Object o where diff --git a/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql b/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql index dc21b250c1e..375e9b9880e 100644 --- a/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql +++ b/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls, string name, string kind, Object o where diff --git a/python/ql/test/library-tests/types/classes/FailedInference.ql b/python/ql/test/library-tests/types/classes/FailedInference.ql index 192cf696fbf..feae8fdc5ee 100644 --- a/python/ql/test/library-tests/types/classes/FailedInference.ql +++ b/python/ql/test/library-tests/types/classes/FailedInference.ql @@ -1,5 +1,5 @@ import python -import semmle.python.pointsto.PointsTo +private import LegacyPointsTo from ClassValue cls, string reason where Types::failedInference(cls, reason) diff --git a/python/ql/test/library-tests/types/classes/duplicate_base.ql b/python/ql/test/library-tests/types/classes/duplicate_base.ql index 47e975c4560..7a32b545ae0 100644 --- a/python/ql/test/library-tests/types/classes/duplicate_base.ql +++ b/python/ql/test/library-tests/types/classes/duplicate_base.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ClassObject cls where cls.hasDuplicateBases() diff --git a/python/ql/test/library-tests/types/exceptions/ExitRaises.ql b/python/ql/test/library-tests/types/exceptions/ExitRaises.ql index 32ef268332c..6ad248f6612 100644 --- a/python/ql/test/library-tests/types/exceptions/ExitRaises.ql +++ b/python/ql/test/library-tests/types/exceptions/ExitRaises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r, Scope s, ClassObject cls where r.viableExceptionalExit_objectapi(s, cls) diff --git a/python/ql/test/library-tests/types/exceptions/Handles.ql b/python/ql/test/library-tests/types/exceptions/Handles.ql index dfdf1f9d7b2..e5a21724975 100644 --- a/python/ql/test/library-tests/types/exceptions/Handles.ql +++ b/python/ql/test/library-tests/types/exceptions/Handles.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ExceptFlowNode n, ClassObject cls where n.handles_objectapi(cls) diff --git a/python/ql/test/library-tests/types/exceptions/Impossible.ql b/python/ql/test/library-tests/types/exceptions/Impossible.ql index 787ba8898f9..acdcbb8e84f 100644 --- a/python/ql/test/library-tests/types/exceptions/Impossible.ql +++ b/python/ql/test/library-tests/types/exceptions/Impossible.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r, ControlFlowNode n, string kind where diff --git a/python/ql/test/library-tests/types/exceptions/LineRaises.ql b/python/ql/test/library-tests/types/exceptions/LineRaises.ql index de8b834e520..94b54a27198 100644 --- a/python/ql/test/library-tests/types/exceptions/LineRaises.ql +++ b/python/ql/test/library-tests/types/exceptions/LineRaises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r, string type where diff --git a/python/ql/test/library-tests/types/exceptions/Raises.ql b/python/ql/test/library-tests/types/exceptions/Raises.ql index 2415c707967..e4f9a6664d5 100644 --- a/python/ql/test/library-tests/types/exceptions/Raises.ql +++ b/python/ql/test/library-tests/types/exceptions/Raises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PyFunctionObject f, string type where diff --git a/python/ql/test/library-tests/types/exceptions/Reraises.ql b/python/ql/test/library-tests/types/exceptions/Reraises.ql index 699eb325f8c..8a6ade33d5a 100644 --- a/python/ql/test/library-tests/types/exceptions/Reraises.ql +++ b/python/ql/test/library-tests/types/exceptions/Reraises.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from ReraisingNode r select r.getLocation().getStartLine(), r, r.getARaisedType().toString() diff --git a/python/ql/test/library-tests/types/exceptions/Viable.ql b/python/ql/test/library-tests/types/exceptions/Viable.ql index bf00a0675d6..589e2630bb9 100644 --- a/python/ql/test/library-tests/types/exceptions/Viable.ql +++ b/python/ql/test/library-tests/types/exceptions/Viable.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from RaisingNode r, ControlFlowNode n, ClassObject ex where r.viableExceptionEdge_objectapi(n, ex) diff --git a/python/ql/test/library-tests/types/properties/Deleters.ql b/python/ql/test/library-tests/types/properties/Deleters.ql index ad99ceb387d..ed98d02b3a8 100644 --- a/python/ql/test/library-tests/types/properties/Deleters.ql +++ b/python/ql/test/library-tests/types/properties/Deleters.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PythonPropertyObject p select p.toString(), p.getDeleter().toString() diff --git a/python/ql/test/library-tests/types/properties/Getters.ql b/python/ql/test/library-tests/types/properties/Getters.ql index 5f232858696..d8c54dbda09 100644 --- a/python/ql/test/library-tests/types/properties/Getters.ql +++ b/python/ql/test/library-tests/types/properties/Getters.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PythonPropertyObject p select p.toString(), p.getGetter().toString() diff --git a/python/ql/test/library-tests/types/properties/PythonProperties.ql b/python/ql/test/library-tests/types/properties/PythonProperties.ql index 858326d6ac0..4440c6df21e 100644 --- a/python/ql/test/library-tests/types/properties/PythonProperties.ql +++ b/python/ql/test/library-tests/types/properties/PythonProperties.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PythonPropertyObject p select p.toString() diff --git a/python/ql/test/library-tests/types/properties/Setters.ql b/python/ql/test/library-tests/types/properties/Setters.ql index 871e6f9145f..5180f58552a 100644 --- a/python/ql/test/library-tests/types/properties/Setters.ql +++ b/python/ql/test/library-tests/types/properties/Setters.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo from PythonPropertyObject p select p.toString(), p.getSetter().toString() From 21e74a3f0187de9aab53f1cff8172ae3472560f3 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 31 Oct 2025 14:05:33 +0000 Subject: [PATCH 10/22] Python: Fully remove points-to from `Flow.qll` Gets rid of a bunch of predicates relating to reachability (which depended on the modelling of exceptions, which uses points-to), moving them to `LegacyPointsTo`. In the process, we gained a new class `BasicBlockWithPointsTo`. --- python/ql/lib/LegacyPointsTo.qll | 57 +++++++++++++++++++++++++ python/ql/lib/semmle/python/Flow.qll | 56 +----------------------- python/ql/lib/semmle/python/Metrics.qll | 4 +- python/ql/lib/semmle/python/SSA.qll | 2 +- 4 files changed, 62 insertions(+), 57 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index cfa73bf47c4..3bc0258bdaa 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -106,6 +106,24 @@ class ControlFlowNodeWithPointsTo extends ControlFlowNode { // for that variable. exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v)) } + + /** Whether it is unlikely that this ControlFlowNode can be reached */ + predicate unlikelyReachable() { + not start_bb_likely_reachable(this.getBasicBlock()) + or + exists(BasicBlock b | + start_bb_likely_reachable(b) and + not end_bb_likely_reachable(b) and + // If there is an unlikely successor edge earlier in the BB + // than this node, then this node must be unreachable. + exists(ControlFlowNode p, int i, int j | + p.(RaisingNode).unlikelySuccessor(_) and + p = b.getNode(i) and + this = b.getNode(j) and + i < j + ) + ) + } } /** @@ -134,6 +152,45 @@ private predicate varHasCompletePointsToSet(SsaVariable var) { ) } +private predicate start_bb_likely_reachable(BasicBlock b) { + exists(Scope s | s.getEntryNode() = b.getNode(_)) + or + exists(BasicBlock pred | + pred = b.getAPredecessor() and + end_bb_likely_reachable(pred) and + not pred.getLastNode().(RaisingNode).unlikelySuccessor(b) + ) +} + +private predicate end_bb_likely_reachable(BasicBlock b) { + start_bb_likely_reachable(b) and + not exists(ControlFlowNode p, ControlFlowNode s | + p.(RaisingNode).unlikelySuccessor(s) and + p = b.getNode(_) and + s = b.getNode(_) and + not p = b.getLastNode() + ) +} + +/** + * An extension of `BasicBlock` that provides points-to related methods. + */ +class BasicBlockWithPointsTo extends BasicBlock { + /** + * Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. + */ + predicate unlikelySuccessor(BasicBlockWithPointsTo succ) { + this.getLastNode().(RaisingNode).unlikelySuccessor(succ.firstNode()) + or + not end_bb_likely_reachable(this) and succ = this.getASuccessor() + } + + /** + * Whether (as inferred by type inference) this basic block is likely to be reachable. + */ + predicate likelyReachable() { start_bb_likely_reachable(this) } +} + /** * An extension of `Expr` that provides points-to predicates. */ diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 6574979f9c8..2994a910888 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -1,7 +1,6 @@ import python private import semmle.python.internal.CachedStages private import codeql.controlflow.BasicBlock as BB -private import LegacyPointsTo /* * Note about matching parent and child nodes and CFG splitting: @@ -191,24 +190,6 @@ class ControlFlowNode extends @py_flow_node { /** Whether this node is a normal (non-exceptional) exit */ predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } - /** Whether it is unlikely that this ControlFlowNode can be reached */ - predicate unlikelyReachable() { - not start_bb_likely_reachable(this.getBasicBlock()) - or - exists(BasicBlock b | - start_bb_likely_reachable(b) and - not end_bb_likely_reachable(b) and - // If there is an unlikely successor edge earlier in the BB - // than this node, then this node must be unreachable. - exists(ControlFlowNode p, int i, int j | - p.(RaisingNode).unlikelySuccessor(_) and - p = b.getNode(i) and - this = b.getNode(j) and - i < j - ) - ) - } - /** Whether this strictly dominates other. */ pragma[inline] predicate strictlyDominates(ControlFlowNode other) { @@ -1005,7 +986,8 @@ class BasicBlock extends @py_flow_node { ) } - private ControlFlowNode firstNode() { result = this } + /** Gets the first node in this basic block */ + ControlFlowNode firstNode() { result = this } /** Gets the last node in this basic block */ ControlFlowNode getLastNode() { @@ -1094,15 +1076,6 @@ class BasicBlock extends @py_flow_node { ) } - /** - * Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. - */ - predicate unlikelySuccessor(BasicBlock succ) { - this.getLastNode().(RaisingNode).unlikelySuccessor(succ.firstNode()) - or - not end_bb_likely_reachable(this) and succ = this.getASuccessor() - } - /** Holds if this basic block strictly reaches the other. Is the start of other reachable from the end of this. */ cached predicate strictlyReaches(BasicBlock other) { @@ -1113,11 +1086,6 @@ class BasicBlock extends @py_flow_node { /** Holds if this basic block reaches the other. Is the start of other reachable from the end of this. */ predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } - /** - * Whether (as inferred by type inference) this basic block is likely to be reachable. - */ - predicate likelyReachable() { start_bb_likely_reachable(this) } - /** * Gets the `ConditionBlock`, if any, that controls this block and * does not control any other `ConditionBlock`s that control this block. @@ -1145,26 +1113,6 @@ class BasicBlock extends @py_flow_node { } } -private predicate start_bb_likely_reachable(BasicBlock b) { - exists(Scope s | s.getEntryNode() = b.getNode(_)) - or - exists(BasicBlock pred | - pred = b.getAPredecessor() and - end_bb_likely_reachable(pred) and - not pred.getLastNode().(RaisingNode).unlikelySuccessor(b) - ) -} - -private predicate end_bb_likely_reachable(BasicBlock b) { - start_bb_likely_reachable(b) and - not exists(ControlFlowNode p, ControlFlowNode s | - p.(RaisingNode).unlikelySuccessor(s) and - p = b.getNode(_) and - s = b.getNode(_) and - not p = b.getLastNode() - ) -} - private class ControlFlowNodeAlias = ControlFlowNode; final private class FinalBasicBlock = BasicBlock; diff --git a/python/ql/lib/semmle/python/Metrics.qll b/python/ql/lib/semmle/python/Metrics.qll index dcc5cf959d9..4959a06317f 100644 --- a/python/ql/lib/semmle/python/Metrics.qll +++ b/python/ql/lib/semmle/python/Metrics.qll @@ -29,9 +29,9 @@ class FunctionMetrics extends Function { */ int getCyclomaticComplexity() { exists(int e, int n | - n = count(BasicBlock b | b = this.getABasicBlock() and b.likelyReachable()) and + n = count(BasicBlockWithPointsTo b | b = this.getABasicBlock() and b.likelyReachable()) and e = - count(BasicBlock b1, BasicBlock b2 | + count(BasicBlockWithPointsTo b1, BasicBlockWithPointsTo b2 | b1 = this.getABasicBlock() and b1.likelyReachable() and b2 = this.getABasicBlock() and diff --git a/python/ql/lib/semmle/python/SSA.qll b/python/ql/lib/semmle/python/SSA.qll index a139f22dfc6..fc98e5975fb 100644 --- a/python/ql/lib/semmle/python/SSA.qll +++ b/python/ql/lib/semmle/python/SSA.qll @@ -92,7 +92,7 @@ class SsaVariable extends @py_ssa_var { } /** Gets the incoming edges for a Phi node, pruned of unlikely edges. */ - private BasicBlock getAPrunedPredecessorBlockForPhi() { + private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() { result = this.getAPredecessorBlockForPhi() and not result.unlikelySuccessor(this.getDefinition().getBasicBlock()) } From 7328f263116193676cedbdcc0dee95ce64809fa0 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 31 Oct 2025 14:22:29 +0000 Subject: [PATCH 11/22] Python: Fix reachability-related test failures --- python/ql/lib/semmle/python/dataflow/old/Implementation.qll | 6 ++++-- python/ql/src/Functions/ConsistentReturns.ql | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/old/Implementation.qll b/python/ql/lib/semmle/python/dataflow/old/Implementation.qll index eb7e5fdc9a5..18020c7d9ff 100644 --- a/python/ql/lib/semmle/python/dataflow/old/Implementation.qll +++ b/python/ql/lib/semmle/python/dataflow/old/Implementation.qll @@ -256,7 +256,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi TaintKind kind, string edgeLabel ) { this.unprunedStep(src, node, context, path, kind, edgeLabel) and - node.getBasicBlock().likelyReachable() and + node.getBasicBlock().(BasicBlockWithPointsTo).likelyReachable() and not super.isBarrier(node) and ( not path = TNoAttribute() @@ -684,7 +684,9 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path, TaintKind kind ) { - exists(DataFlow::Node srcnode, BasicBlock pred, EssaVariable predvar, DataFlow::Node phi | + exists( + DataFlow::Node srcnode, BasicBlockWithPointsTo pred, EssaVariable predvar, DataFlow::Node phi + | src = TTaintTrackingNode_(srcnode, context, path, kind, this) and defn = phi.asVariable().getDefinition() and predvar = defn.getInput(pred) and diff --git a/python/ql/src/Functions/ConsistentReturns.ql b/python/ql/src/Functions/ConsistentReturns.ql index 1bc7b5724b3..9beeafc6372 100644 --- a/python/ql/src/Functions/ConsistentReturns.ql +++ b/python/ql/src/Functions/ConsistentReturns.ql @@ -12,6 +12,7 @@ */ import python +private import LegacyPointsTo predicate explicitly_returns_non_none(Function func) { exists(Return return | @@ -21,7 +22,7 @@ predicate explicitly_returns_non_none(Function func) { } predicate has_implicit_return(Function func) { - exists(ControlFlowNode fallthru | + exists(ControlFlowNodeWithPointsTo fallthru | fallthru = func.getFallthroughNode() and not fallthru.unlikelyReachable() ) or From e09840426c24fed32432f5f4f9fd17079425c246 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 31 Oct 2025 14:56:13 +0000 Subject: [PATCH 12/22] Python: Get rid of points-to from `Definitions.qll` Turns out the `ImportTime` module (despite living in `semmle.python.types` does not actually depend on points-to, so some of the `LegacyPointsTo` imports could be replaced or removed. --- python/ql/lib/LegacyPointsTo.qll | 1 - python/ql/lib/analysis/DefinitionTracking.qll | 1 + python/ql/lib/semmle/python/essa/Definitions.qll | 2 +- python/ql/src/Imports/Cyclic.qll | 1 + python/ql/src/Imports/UnintentionalImport.ql | 1 + python/ql/src/Variables/UndefinedGlobal.ql | 1 + python/ql/src/Variables/UndefinedPlaceHolder.ql | 1 + python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql | 1 + 8 files changed, 7 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index 3bc0258bdaa..9e6efdb29cf 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -32,7 +32,6 @@ import semmle.python.types.FunctionObject import semmle.python.types.ModuleObject import semmle.python.types.Exceptions import semmle.python.types.Properties -import semmle.python.types.ImportTime import semmle.python.types.Descriptors import semmle.python.SelfAttribute diff --git a/python/ql/lib/analysis/DefinitionTracking.qll b/python/ql/lib/analysis/DefinitionTracking.qll index c019e92c0ca..0d58bd69b7b 100644 --- a/python/ql/lib/analysis/DefinitionTracking.qll +++ b/python/ql/lib/analysis/DefinitionTracking.qll @@ -4,6 +4,7 @@ import python private import LegacyPointsTo +private import semmle.python.types.ImportTime import IDEContextual private newtype TDefinition = diff --git a/python/ql/lib/semmle/python/essa/Definitions.qll b/python/ql/lib/semmle/python/essa/Definitions.qll index 17b4e622ea1..aca6991b9f6 100644 --- a/python/ql/lib/semmle/python/essa/Definitions.qll +++ b/python/ql/lib/semmle/python/essa/Definitions.qll @@ -11,7 +11,7 @@ import python * Escaping globals -- Global variables that have definitions and at least one of those definitions is in another scope. */ -private import LegacyPointsTo +private import semmle.python.types.ImportTime private import semmle.python.essa.SsaDefinitions /** A source language variable, to be converted into a set of SSA variables. */ diff --git a/python/ql/src/Imports/Cyclic.qll b/python/ql/src/Imports/Cyclic.qll index 720ea8f0048..ad24a08eddd 100644 --- a/python/ql/src/Imports/Cyclic.qll +++ b/python/ql/src/Imports/Cyclic.qll @@ -1,5 +1,6 @@ import python private import LegacyPointsTo +private import semmle.python.types.ImportTime predicate is_import_time(Stmt s) { not s.getScope+() instanceof Function } diff --git a/python/ql/src/Imports/UnintentionalImport.ql b/python/ql/src/Imports/UnintentionalImport.ql index 7b22865cd89..db1775a0d41 100644 --- a/python/ql/src/Imports/UnintentionalImport.ql +++ b/python/ql/src/Imports/UnintentionalImport.ql @@ -14,6 +14,7 @@ import python private import LegacyPointsTo +private import semmle.python.types.ImportTime predicate import_star(ImportStar imp, ModuleValue exporter) { exporter.importedAs(imp.getImportedModuleName()) diff --git a/python/ql/src/Variables/UndefinedGlobal.ql b/python/ql/src/Variables/UndefinedGlobal.ql index bfe816d5c58..2fdf708a2b9 100644 --- a/python/ql/src/Variables/UndefinedGlobal.ql +++ b/python/ql/src/Variables/UndefinedGlobal.ql @@ -12,6 +12,7 @@ import python private import LegacyPointsTo +private import semmle.python.types.ImportTime import Variables.MonkeyPatched import Loop diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index 11bf3b6d0be..4b21e371977 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -14,6 +14,7 @@ import python import Variables.MonkeyPatched private import LegacyPointsTo +private import semmle.python.types.ImportTime /* Local variable part */ predicate initialized_as_local(PlaceHolder use) { diff --git a/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql index e90674bab2e..a0b7e8979f3 100644 --- a/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql @@ -1,5 +1,6 @@ import python private import LegacyPointsTo +private import semmle.python.types.ImportTime import interesting from int line, ControlFlowNodeWithPointsTo f, Object o, ImportTimeScope n From 9dc774aaa3ff00e76e81851732fdc6f99ffde237 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 31 Oct 2025 15:52:53 +0000 Subject: [PATCH 13/22] Python: Remove points-to dependency from parts of SSA For whatever reason, the CFG node for exceptions and exception groups was placed with the points-to code. (Probably because a lot of the predicates depended on points-to.) However, as it turned out, two of the SSA modules only depended on non-points-to properties of these nodes, and so it was fairly straightforward to remove the imports of `LegacyPointsTo` for those modules. In the process, I moved the aforementioned CFG node types into `Flow.qll`, and changed the classes in the `Exceptions` module to the `...WithPointsTo` form that we introduced elsewhere. --- python/ql/lib/semmle/python/Flow.qll | 52 +++++++++++++ python/ql/lib/semmle/python/essa/Essa.qll | 1 - .../lib/semmle/python/essa/SsaDefinitions.qll | 1 - .../ql/lib/semmle/python/types/Exceptions.qll | 76 ++++--------------- .../Exceptions/IllegalExceptionHandlerType.ql | 2 +- .../ControlFlow/Exceptions/Handles.ql | 2 +- .../ControlFlow/Exceptions/Handles.ql | 2 +- .../test/library-tests/exceptions/Handles.ql | 2 +- .../library-tests/types/exceptions/Handles.ql | 2 +- 9 files changed, 70 insertions(+), 70 deletions(-) diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 2994a910888..898cd566ab9 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -883,6 +883,58 @@ class StarredNode extends ControlFlowNode { ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() } } +/** The ControlFlowNode for an 'except' statement. */ +class ExceptFlowNode extends ControlFlowNode { + ExceptFlowNode() { this.getNode() instanceof ExceptStmt } + + /** + * Gets the type handled by this exception handler. + * `ExceptionType` in `except ExceptionType as e:` + */ + ControlFlowNode getType() { + exists(ExceptStmt ex | + this.getBasicBlock().dominates(result.getBasicBlock()) and + ex = this.getNode() and + result = ex.getType().getAFlowNode() + ) + } + + /** + * Gets the name assigned to the handled exception, if any. + * `e` in `except ExceptionType as e:` + */ + ControlFlowNode getName() { + exists(ExceptStmt ex | + this.getBasicBlock().dominates(result.getBasicBlock()) and + ex = this.getNode() and + result = ex.getName().getAFlowNode() + ) + } +} + +/** The ControlFlowNode for an 'except*' statement. */ +class ExceptGroupFlowNode extends ControlFlowNode { + ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt } + + /** + * Gets the type handled by this exception handler. + * `ExceptionType` in `except* ExceptionType as e:` + */ + ControlFlowNode getType() { + this.getBasicBlock().dominates(result.getBasicBlock()) and + result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode() + } + + /** + * Gets the name assigned to the handled exception, if any. + * `e` in `except* ExceptionType as e:` + */ + ControlFlowNode getName() { + this.getBasicBlock().dominates(result.getBasicBlock()) and + result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode() + } +} + private module Scopes { private predicate fast_local(NameNode n) { exists(FastLocalVariable v | diff --git a/python/ql/lib/semmle/python/essa/Essa.qll b/python/ql/lib/semmle/python/essa/Essa.qll index 1b83f8df6ac..384bfd2f91f 100644 --- a/python/ql/lib/semmle/python/essa/Essa.qll +++ b/python/ql/lib/semmle/python/essa/Essa.qll @@ -6,7 +6,6 @@ import python private import SsaCompute import semmle.python.essa.Definitions private import semmle.python.internal.CachedStages -private import LegacyPointsTo private import semmle.python.essa.SsaDefinitions /** An (enhanced) SSA variable derived from `SsaSourceVariable`. */ diff --git a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll index b263287d05d..6c87af102fa 100644 --- a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll +++ b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll @@ -5,7 +5,6 @@ import python private import semmle.python.internal.CachedStages -private import LegacyPointsTo /** Hold if `expr` is a test (a branch) and `use` is within that test */ predicate test_contains(ControlFlowNode expr, ControlFlowNode use) { diff --git a/python/ql/lib/semmle/python/types/Exceptions.qll b/python/ql/lib/semmle/python/types/Exceptions.qll index 5e982aa0134..dd9ee1703a6 100644 --- a/python/ql/lib/semmle/python/types/Exceptions.qll +++ b/python/ql/lib/semmle/python/types/Exceptions.qll @@ -80,7 +80,7 @@ class RaisingNode extends ControlFlowNode { or this.getNode() instanceof Print and result = theIOErrorType() or - exists(ExceptFlowNode except | + exists(ExceptFlowNodeWithPointsTo except | except = this.getAnExceptionalSuccessor() and except.handles_objectapi(result) and result = this.innateException_objectapi() @@ -107,7 +107,7 @@ class RaisingNode extends ControlFlowNode { or this.getNode() instanceof Print and result = ClassValue::ioError() or - exists(ExceptFlowNode except | + exists(ExceptFlowNodeWithPointsTo except | except = this.getAnExceptionalSuccessor() and except.handles(result) and result = this.innateException() @@ -200,8 +200,8 @@ class RaisingNode extends ControlFlowNode { succ = this.getAnExceptionalSuccessor() and ( /* An 'except' that handles raised and there is no more previous handler */ - succ.(ExceptFlowNode).handles_objectapi(raised) and - not exists(ExceptFlowNode other, StmtList s, int i, int j | + succ.(ExceptFlowNodeWithPointsTo).handles_objectapi(raised) and + not exists(ExceptFlowNodeWithPointsTo other, StmtList s, int i, int j | not other = succ and other.handles_objectapi(raised) and s.getItem(i) = succ.getNode() and @@ -211,7 +211,7 @@ class RaisingNode extends ControlFlowNode { ) or /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */ - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) and + not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles_objectapi(raised) and not succ instanceof ExceptFlowNode ) } @@ -223,8 +223,8 @@ class RaisingNode extends ControlFlowNode { succ = this.getAnExceptionalSuccessor() and ( /* An 'except' that handles raised and there is no more previous handler */ - succ.(ExceptFlowNode).handles(raised) and - not exists(ExceptFlowNode other, StmtList s, int i, int j | + succ.(ExceptFlowNodeWithPointsTo).handles(raised) and + not exists(ExceptFlowNodeWithPointsTo other, StmtList s, int i, int j | not other = succ and other.handles(raised) and s.getItem(i) = succ.getNode() and @@ -234,7 +234,7 @@ class RaisingNode extends ControlFlowNode { ) or /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */ - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) and + not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles(raised) and not succ instanceof ExceptFlowNode ) } @@ -248,7 +248,7 @@ class RaisingNode extends ControlFlowNode { raised.isLegalExceptionType() and raised = this.getARaisedType_objectapi() and this.isExceptionalExit(s) and - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) + not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles_objectapi(raised) } /** @@ -260,7 +260,7 @@ class RaisingNode extends ControlFlowNode { raised.isLegalExceptionType() and raised = this.getARaisedType() and this.isExceptionalExit(s) and - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) + not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles(raised) } } @@ -368,36 +368,9 @@ predicate scope_raises_unknown(Scope s) { ) } -/** The ControlFlowNode for an 'except' statement. */ -class ExceptFlowNode extends ControlFlowNode { - ExceptFlowNode() { this.getNode() instanceof ExceptStmt } - - /** - * Gets the type handled by this exception handler. - * `ExceptionType` in `except ExceptionType as e:` - */ - ControlFlowNodeWithPointsTo getType() { - exists(ExceptStmt ex | - this.getBasicBlock().dominates(result.getBasicBlock()) and - ex = this.getNode() and - result = ex.getType().getAFlowNode() - ) - } - - /** - * Gets the name assigned to the handled exception, if any. - * `e` in `except ExceptionType as e:` - */ - ControlFlowNode getName() { - exists(ExceptStmt ex | - this.getBasicBlock().dominates(result.getBasicBlock()) and - ex = this.getNode() and - result = ex.getName().getAFlowNode() - ) - } - +class ExceptFlowNodeWithPointsTo extends ExceptFlowNode { private predicate handledObject_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) { - this.getType().refersTo(obj, cls, origin) + this.getType().(ControlFlowNodeWithPointsTo).refersTo(obj, cls, origin) or exists(Object tup | this.handledObject_objectapi(tup, theTupleType(), _) | element_from_tuple_objectapi(tup).refersTo(obj, cls, origin) @@ -407,7 +380,7 @@ class ExceptFlowNode extends ControlFlowNode { private predicate handledObject(Value val, ClassValue cls, ControlFlowNode origin) { val.getClass() = cls and ( - this.getType().pointsTo(val, origin) + this.getType().(ControlFlowNodeWithPointsTo).pointsTo(val, origin) or exists(TupleValue tup | this.handledObject(tup, ClassValue::tuple(), _) | val = tup.getItem(_) and origin = val.getOrigin() @@ -452,29 +425,6 @@ class ExceptFlowNode extends ControlFlowNode { } } -/** The ControlFlowNode for an 'except*' statement. */ -class ExceptGroupFlowNode extends ControlFlowNode { - ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt } - - /** - * Gets the type handled by this exception handler. - * `ExceptionType` in `except* ExceptionType as e:` - */ - ControlFlowNode getType() { - this.getBasicBlock().dominates(result.getBasicBlock()) and - result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode() - } - - /** - * Gets the name assigned to the handled exception, if any. - * `e` in `except* ExceptionType as e:` - */ - ControlFlowNode getName() { - this.getBasicBlock().dominates(result.getBasicBlock()) and - result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode() - } -} - private ControlFlowNodeWithPointsTo element_from_tuple_objectapi(Object tuple) { exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode()) } diff --git a/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql b/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql index b5446dccbfc..dc1c3f2fa35 100644 --- a/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql +++ b/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql @@ -14,7 +14,7 @@ import python private import LegacyPointsTo -from ExceptFlowNode ex, Value t, ClassValue c, ControlFlowNode origin, string what +from ExceptFlowNodeWithPointsTo ex, Value t, ClassValue c, ControlFlowNode origin, string what where ex.handledException(t, c, origin) and ( diff --git a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql index 60989ff8645..a8bc92db331 100644 --- a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql +++ b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Handles.ql @@ -1,6 +1,6 @@ import python private import LegacyPointsTo -from ExceptFlowNode ex, Value val +from ExceptFlowNodeWithPointsTo ex, Value val where ex.handledException(val, _, _) select ex.getLocation().getStartLine(), ex.toString(), val.toString() diff --git a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql index 60989ff8645..a8bc92db331 100644 --- a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql +++ b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Handles.ql @@ -1,6 +1,6 @@ import python private import LegacyPointsTo -from ExceptFlowNode ex, Value val +from ExceptFlowNodeWithPointsTo ex, Value val where ex.handledException(val, _, _) select ex.getLocation().getStartLine(), ex.toString(), val.toString() diff --git a/python/ql/test/library-tests/exceptions/Handles.ql b/python/ql/test/library-tests/exceptions/Handles.ql index 60989ff8645..a8bc92db331 100644 --- a/python/ql/test/library-tests/exceptions/Handles.ql +++ b/python/ql/test/library-tests/exceptions/Handles.ql @@ -1,6 +1,6 @@ import python private import LegacyPointsTo -from ExceptFlowNode ex, Value val +from ExceptFlowNodeWithPointsTo ex, Value val where ex.handledException(val, _, _) select ex.getLocation().getStartLine(), ex.toString(), val.toString() diff --git a/python/ql/test/library-tests/types/exceptions/Handles.ql b/python/ql/test/library-tests/types/exceptions/Handles.ql index e5a21724975..bec8767d6c5 100644 --- a/python/ql/test/library-tests/types/exceptions/Handles.ql +++ b/python/ql/test/library-tests/types/exceptions/Handles.ql @@ -1,6 +1,6 @@ import python private import LegacyPointsTo -from ExceptFlowNode n, ClassObject cls +from ExceptFlowNodeWithPointsTo n, ClassObject cls where n.handles_objectapi(cls) select n.getLocation().getStartLine(), cls.toString() From 5b47fcbfa4152283c41f5a9973b2496815508434 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 31 Oct 2025 16:16:22 +0000 Subject: [PATCH 14/22] Python: Remove dependence on `Builtins` from attribute module The `Builtins` module is deeply entwined with points-to, so it would be nice to not have this dependence. Happily, the only thing we used `Builtin` for was to get the names of known builtins, and for this we already maintain such a set of names in `dataflow.new.internal.Builtins`. --- .../python/dataflow/new/internal/Attributes.qll | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll index 42c0c862e89..e9bcc5e6785 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll @@ -1,9 +1,10 @@ /** This module provides an API for attribute reads and writes. */ +private import python import DataFlowUtil import DataFlowPublic private import DataFlowPrivate -private import semmle.python.types.Builtins +private import semmle.python.dataflow.new.internal.Builtins /** * A data flow node that reads or writes an attribute of an object. @@ -134,8 +135,12 @@ private class BuiltInCallNode extends CallNode { BuiltInCallNode() { // TODO disallow instances where the name of the built-in may refer to an in-scope variable of that name. - exists(NameNode id | this.getFunction() = id and id.getId() = name and id.isGlobal()) and - name = any(Builtin b).getName() + exists(NameNode id | + name = Builtins::getBuiltinName() and + this.getFunction() = id and + id.getId() = name and + id.isGlobal() + ) } /** Gets the name of the built-in function that is called at this `CallNode` */ From b9a5b3b628b699f7415f8b4738191f613c041f5a Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 26 Nov 2025 13:55:20 +0000 Subject: [PATCH 15/22] Python: Remove points-to from `SSA.ql` Happily, this was not as deeply entwined as it looked at first glance. --- python/ql/lib/LegacyPointsTo.qll | 88 +++++++++++++++++++++++++++++ python/ql/lib/semmle/python/SSA.qll | 86 +--------------------------- 2 files changed, 89 insertions(+), 85 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index 9e6efdb29cf..99b49a91986 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -340,3 +340,91 @@ Object getLiteralObject(ImmutableLiteral l) { name_consts(l, "None") and result = theNoneObject() } + +private predicate gettext_installed() { + // Good enough (and fast) approximation + exists(Module m | m.getName() = "gettext") +} + +private predicate builtin_constant(string name) { + exists(Object::builtin(name)) + or + name = "WindowsError" + or + name = "_" and gettext_installed() +} + +/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */ +predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) } + +private predicate auto_name(string name) { + name = "__file__" or name = "__builtins__" or name = "__name__" +} + +/** An extension of `SsaVariable` that provides points-to related methods. */ +class SsaVariableWithPointsTo extends SsaVariable { + /** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */ + SsaVariable getAPrunedPhiInput() { + result = this.getAPhiInput() and + exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) | + not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition()) + ) + } + + /** Gets the incoming edges for a Phi node, pruned of unlikely edges. */ + private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() { + result = this.getAPredecessorBlockForPhi() and + not result.unlikelySuccessor(this.getDefinition().getBasicBlock()) + } + + private predicate implicitlyDefined() { + not exists(this.getDefinition()) and + not py_ssa_phi(this, _) and + exists(GlobalVariable var | this.getVariable() = var | + globallyDefinedName(var.getId()) + or + var.getId() = "__path__" and var.getScope().(Module).isPackageInit() + ) + } + + /** Whether this variable may be undefined */ + predicate maybeUndefined() { + not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined() + or + this.getDefinition().isDelete() + or + exists(SsaVariableWithPointsTo var | var = this.getAPrunedPhiInput() | var.maybeUndefined()) + or + /* + * For phi-nodes, there must be a corresponding phi-input for each control-flow + * predecessor. Otherwise, the variable will be undefined on that incoming edge. + * WARNING: the same phi-input may cover multiple predecessors, so this check + * cannot be done by counting. + */ + + exists(BasicBlock incoming | + reaches_end(incoming) and + incoming = this.getAPrunedPredecessorBlockForPhi() and + not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) + ) + } + + override string getAQlClass() { none() } +} + +private predicate reaches_end(BasicBlock b) { + not exits_early(b) and + ( + /* Entry point */ + not exists(BasicBlock prev | prev.getASuccessor() = b) + or + exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev)) + ) +} + +private predicate exits_early(BasicBlock b) { + exists(FunctionObject f | + f.neverReturns() and + f.getACall().getBasicBlock() = b + ) +} diff --git a/python/ql/lib/semmle/python/SSA.qll b/python/ql/lib/semmle/python/SSA.qll index fc98e5975fb..b71bd95de79 100644 --- a/python/ql/lib/semmle/python/SSA.qll +++ b/python/ql/lib/semmle/python/SSA.qll @@ -1,7 +1,6 @@ /** SSA library */ import python -private import LegacyPointsTo /** * A single static assignment variable. @@ -62,14 +61,6 @@ class SsaVariable extends @py_ssa_var { ) } - /** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */ - SsaVariable getAPrunedPhiInput() { - result = this.getAPhiInput() and - exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) | - not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition()) - ) - } - /** Gets a variable that ultimately defines this variable and is not itself defined by another variable */ SsaVariable getAnUltimateDefinition() { result = this and not exists(this.getAPhiInput()) @@ -86,17 +77,11 @@ class SsaVariable extends @py_ssa_var { string getId() { result = this.getVariable().getId() } /** Gets the incoming edges for a Phi node. */ - private BasicBlock getAPredecessorBlockForPhi() { + BasicBlock getAPredecessorBlockForPhi() { exists(this.getAPhiInput()) and result.getASuccessor() = this.getDefinition().getBasicBlock() } - /** Gets the incoming edges for a Phi node, pruned of unlikely edges. */ - private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() { - result = this.getAPredecessorBlockForPhi() and - not result.unlikelySuccessor(this.getDefinition().getBasicBlock()) - } - /** Whether it is possible to reach a use of this variable without passing a definition */ predicate reachableWithoutDefinition() { not exists(this.getDefinition()) and not py_ssa_phi(this, _) @@ -116,38 +101,6 @@ class SsaVariable extends @py_ssa_var { ) } - /** Whether this variable may be undefined */ - predicate maybeUndefined() { - not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined() - or - this.getDefinition().isDelete() - or - exists(SsaVariable var | var = this.getAPrunedPhiInput() | var.maybeUndefined()) - or - /* - * For phi-nodes, there must be a corresponding phi-input for each control-flow - * predecessor. Otherwise, the variable will be undefined on that incoming edge. - * WARNING: the same phi-input may cover multiple predecessors, so this check - * cannot be done by counting. - */ - - exists(BasicBlock incoming | - reaches_end(incoming) and - incoming = this.getAPrunedPredecessorBlockForPhi() and - not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) - ) - } - - private predicate implicitlyDefined() { - not exists(this.getDefinition()) and - not py_ssa_phi(this, _) and - exists(GlobalVariable var | this.getVariable() = var | - globallyDefinedName(var.getId()) - or - var.getId() = "__path__" and var.getScope().(Module).isPackageInit() - ) - } - /** * Gets the global variable that is accessed if this local is undefined. * Only applies to local variables in class scopes. @@ -174,43 +127,6 @@ class SsaVariable extends @py_ssa_var { } } -private predicate reaches_end(BasicBlock b) { - not exits_early(b) and - ( - /* Entry point */ - not exists(BasicBlock prev | prev.getASuccessor() = b) - or - exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev)) - ) -} - -private predicate exits_early(BasicBlock b) { - exists(FunctionObject f | - f.neverReturns() and - f.getACall().getBasicBlock() = b - ) -} - -private predicate gettext_installed() { - // Good enough (and fast) approximation - exists(Module m | m.getName() = "gettext") -} - -private predicate builtin_constant(string name) { - exists(Object::builtin(name)) - or - name = "WindowsError" - or - name = "_" and gettext_installed() -} - -private predicate auto_name(string name) { - name = "__file__" or name = "__builtins__" or name = "__name__" -} - -/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */ -predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) } - /** An SSA variable that is backed by a global variable */ class GlobalSsaVariable extends EssaVariable { GlobalSsaVariable() { this.getSourceVariable() instanceof GlobalVariable } From cd1619b43e97cc6425f5f5b7e7989ef595cffd03 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 26 Nov 2025 13:59:23 +0000 Subject: [PATCH 16/22] Python: Fix queries and tests --- python/ql/src/Statements/RedundantAssignment.ql | 2 +- python/ql/src/Variables/UndefinedGlobal.ql | 4 ++-- python/ql/src/Variables/UndefinedPlaceHolder.ql | 4 +++- .../ql/test/library-tests/ControlFlow/ssa/undefined/test.ql | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/ql/src/Statements/RedundantAssignment.ql b/python/ql/src/Statements/RedundantAssignment.ql index 357364c41b2..a443e199b1c 100644 --- a/python/ql/src/Statements/RedundantAssignment.ql +++ b/python/ql/src/Statements/RedundantAssignment.ql @@ -36,7 +36,7 @@ predicate same_value(Expr left, Expr right) { } predicate maybe_defined_in_outer_scope(Name n) { - exists(SsaVariable v | v.getAUse().getNode() = n | v.maybeUndefined()) + exists(SsaVariableWithPointsTo v | v.getAUse().getNode() = n | v.maybeUndefined()) } /* diff --git a/python/ql/src/Variables/UndefinedGlobal.ql b/python/ql/src/Variables/UndefinedGlobal.ql index 2fdf708a2b9..404ac64aa5a 100644 --- a/python/ql/src/Variables/UndefinedGlobal.ql +++ b/python/ql/src/Variables/UndefinedGlobal.ql @@ -62,7 +62,7 @@ predicate undefined_use_in_function(Name u) { not u.getEnclosingModule().(ImportTimeScope).definesName(u.getId()) and not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and not globallyDefinedName(u.getId()) and - not exists(SsaVariable var | var.getAUse().getNode() = u and not var.maybeUndefined()) and + not exists(SsaVariableWithPointsTo var | var.getAUse().getNode() = u and not var.maybeUndefined()) and not guarded_against_name_error(u) and not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") } @@ -70,7 +70,7 @@ predicate undefined_use_in_function(Name u) { predicate undefined_use_in_class_or_module(Name u) { exists(GlobalVariable v | u.uses(v)) and not u.getScope().getScope*() instanceof Function and - exists(SsaVariable var | var.getAUse().getNode() = u | var.maybeUndefined()) and + exists(SsaVariableWithPointsTo var | var.getAUse().getNode() = u | var.maybeUndefined()) and not guarded_against_name_error(u) and not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") and diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index 4b21e371977..29f9b3a1a51 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -18,7 +18,9 @@ private import semmle.python.types.ImportTime /* Local variable part */ predicate initialized_as_local(PlaceHolder use) { - exists(SsaVariable l, Function f | f = use.getScope() and l.getAUse() = use.getAFlowNode() | + exists(SsaVariableWithPointsTo l, Function f | + f = use.getScope() and l.getAUse() = use.getAFlowNode() + | l.getVariable() instanceof LocalVariable and not l.maybeUndefined() ) diff --git a/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql index 41b08ec0591..c161c5d3f5e 100644 --- a/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql +++ b/python/ql/test/library-tests/ControlFlow/ssa/undefined/test.ql @@ -1,5 +1,6 @@ import python +private import LegacyPointsTo -from SsaVariable var +from SsaVariableWithPointsTo var where var.maybeUndefined() select var.getDefinition().getLocation().getStartLine(), var.toString() From c75329d7b740f7f6f46cf9c22f91b73d96550ca0 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 26 Nov 2025 17:01:50 +0000 Subject: [PATCH 17/22] Python: Move metrics-related API to `LegacyPointsTo` module Gets rid of the `getMetrics` methods on the `Function`, `Class`, and `Module` classes. To access the metrics, one must first import the `LegacyPointsTo` module, and then either change the type to `{Function,Class,Module}Metrics` or cast to the appropriate type. --- python/ql/lib/LegacyPointsTo.qll | 1 + python/ql/lib/python.qll | 2 +- python/ql/lib/semmle/python/Class.qll | 3 --- python/ql/lib/semmle/python/Function.qll | 3 --- python/ql/lib/semmle/python/Module.qll | 3 --- 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index 99b49a91986..c5821f3d009 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -34,6 +34,7 @@ import semmle.python.types.Exceptions import semmle.python.types.Properties import semmle.python.types.Descriptors import semmle.python.SelfAttribute +import semmle.python.Metrics /** * An extension of `ControlFlowNode` that provides points-to predicates. diff --git a/python/ql/lib/python.qll b/python/ql/lib/python.qll index d127e297dbb..54306408a33 100644 --- a/python/ql/lib/python.qll +++ b/python/ql/lib/python.qll @@ -14,7 +14,7 @@ import semmle.python.Patterns import semmle.python.Keywords import semmle.python.Comprehensions import semmle.python.Flow -import semmle.python.Metrics +private import semmle.python.Metrics import semmle.python.Constants import semmle.python.Scope import semmle.python.Comment diff --git a/python/ql/lib/semmle/python/Class.qll b/python/ql/lib/semmle/python/Class.qll index dd7da9ee041..19b81e86a12 100644 --- a/python/ql/lib/semmle/python/Class.qll +++ b/python/ql/lib/semmle/python/Class.qll @@ -147,9 +147,6 @@ class Class extends Class_, Scope, AstNode { /** Gets a base of this class definition. */ Expr getABase() { result = this.getParent().getABase() } - /** Gets the metrics for this class */ - ClassMetrics getMetrics() { result = this } - /** * Gets the qualified name for this class. * Should return the same name as the `__qualname__` attribute on classes in Python 3. diff --git a/python/ql/lib/semmle/python/Function.qll b/python/ql/lib/semmle/python/Function.qll index a5d122c3de7..e15d28d3a12 100644 --- a/python/ql/lib/semmle/python/Function.qll +++ b/python/ql/lib/semmle/python/Function.qll @@ -84,9 +84,6 @@ class Function extends Function_, Scope, AstNode { /** Gets the name used to define this function */ override string getName() { result = Function_.super.getName() } - /** Gets the metrics for this function */ - FunctionMetrics getMetrics() { result = this } - /** * Whether this function is a procedure, that is, it has no explicit return statement and always returns None. * Note that generator and async functions are not procedures as they return generators and coroutines respectively. diff --git a/python/ql/lib/semmle/python/Module.qll b/python/ql/lib/semmle/python/Module.qll index 666217874b7..f22f0d6fe39 100644 --- a/python/ql/lib/semmle/python/Module.qll +++ b/python/ql/lib/semmle/python/Module.qll @@ -86,9 +86,6 @@ class Module extends Module_, Scope, AstNode { result = this.getName().regexpReplaceAll("\\.[^.]*$", "") } - /** Gets the metrics for this module */ - ModuleMetrics getMetrics() { result = this } - string getAnImportedModuleName() { exists(Import i | i.getEnclosingModule() = this | result = i.getAnImportedModuleName()) or From 24a29f46be34473a9d3042e7891b2dc67de3c649 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 26 Nov 2025 17:03:03 +0000 Subject: [PATCH 18/22] Python: Fix all metrics-related compilation failures In hindsight, having a `.getMetrics()` method that just returns `this` is somewhat weird. It's possible that it predates the existence of the inline cast, however. --- python/ql/src/Functions/OverlyComplexDelMethod.ql | 2 +- python/ql/src/Metrics/CLinesOfCode.ql | 5 +++-- python/ql/src/Metrics/ClassAfferentCoupling.ql | 1 + python/ql/src/Metrics/ClassEfferentCoupling.ql | 1 + python/ql/src/Metrics/CommentRatio.ql | 8 +++++--- python/ql/src/Metrics/CyclomaticComplexity.ql | 5 +++-- python/ql/src/Metrics/DocStringRatio.ql | 7 ++++--- python/ql/src/Metrics/FLines.ql | 5 +++-- python/ql/src/Metrics/FLinesOfCode.ql | 5 +++-- python/ql/src/Metrics/FLinesOfComments.ql | 6 +++--- python/ql/src/Metrics/FunctionNumberOfCalls.ql | 1 + python/ql/src/Metrics/FunctionStatementNestingDepth.ql | 1 + python/ql/src/Metrics/History/HChurn.ql | 5 +++-- python/ql/src/Metrics/History/HLinesAdded.ql | 5 +++-- python/ql/src/Metrics/History/HLinesDeleted.ql | 5 +++-- python/ql/src/Metrics/History/HNumberOfAuthors.ql | 5 +++-- python/ql/src/Metrics/History/HNumberOfCoCommits.ql | 5 +++-- python/ql/src/Metrics/History/HNumberOfReCommits.ql | 5 +++-- python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql | 5 +++-- .../ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql | 5 +++-- python/ql/src/Metrics/LackofCohesionInMethodsCK.ql | 1 + python/ql/src/Metrics/LackofCohesionInMethodsHM.ql | 1 + python/ql/src/Metrics/ModuleAfferentCoupling.ql | 1 + python/ql/src/Metrics/ModuleEfferentCoupling.ql | 1 + python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql | 1 + python/ql/src/Statements/DocStrings.ql | 4 ++-- python/ql/src/Summary/LinesOfCode.ql | 3 ++- python/ql/src/Summary/LinesOfUserCode.ql | 5 +++-- python/ql/src/analysis/Summary.ql | 1 + python/ql/src/meta/debug/DebugStats.ql | 6 +++--- .../ql/test/library-tests/ControlFlow/general/Comments.ql | 5 +++-- python/ql/test/library-tests/ControlFlow/general/Cyclo.ql | 5 +++-- python/ql/test/library-tests/ControlFlow/general/Lines.ql | 5 +++-- python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql | 7 ++++--- 34 files changed, 82 insertions(+), 51 deletions(-) diff --git a/python/ql/src/Functions/OverlyComplexDelMethod.ql b/python/ql/src/Functions/OverlyComplexDelMethod.ql index d9fa3e750e6..12776db1b60 100644 --- a/python/ql/src/Functions/OverlyComplexDelMethod.ql +++ b/python/ql/src/Functions/OverlyComplexDelMethod.ql @@ -18,6 +18,6 @@ from FunctionValue method where exists(ClassValue c | c.declaredAttribute("__del__") = method and - method.getScope().getMetrics().getCyclomaticComplexity() > 3 + method.getScope().(FunctionMetrics).getCyclomaticComplexity() > 3 ) select method, "Overly complex '__del__' method." diff --git a/python/ql/src/Metrics/CLinesOfCode.ql b/python/ql/src/Metrics/CLinesOfCode.ql index c7b29615593..66a107a521f 100644 --- a/python/ql/src/Metrics/CLinesOfCode.ql +++ b/python/ql/src/Metrics/CLinesOfCode.ql @@ -10,6 +10,7 @@ */ import python +private import LegacyPointsTo -from Function f -select f, f.getMetrics().getNumberOfLinesOfCode() as n order by n desc +from FunctionMetrics f +select f, f.getNumberOfLinesOfCode() as n order by n desc diff --git a/python/ql/src/Metrics/ClassAfferentCoupling.ql b/python/ql/src/Metrics/ClassAfferentCoupling.ql index 295e8c61a6c..3faf714d09c 100644 --- a/python/ql/src/Metrics/ClassAfferentCoupling.ql +++ b/python/ql/src/Metrics/ClassAfferentCoupling.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ClassMetrics cls select cls, cls.getAfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/ClassEfferentCoupling.ql b/python/ql/src/Metrics/ClassEfferentCoupling.ql index d960c0142e3..b4c5a29696b 100644 --- a/python/ql/src/Metrics/ClassEfferentCoupling.ql +++ b/python/ql/src/Metrics/ClassEfferentCoupling.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ClassMetrics cls select cls, cls.getEfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/CommentRatio.ql b/python/ql/src/Metrics/CommentRatio.ql index 8ebb27cf304..38394c1bf4f 100644 --- a/python/ql/src/Metrics/CommentRatio.ql +++ b/python/ql/src/Metrics/CommentRatio.ql @@ -12,8 +12,10 @@ */ import python +private import LegacyPointsTo -from Module m, ModuleMetrics mm -where mm = m.getMetrics() and mm.getNumberOfLines() > 0 -select m, 100.0 * (mm.getNumberOfLinesOfComments().(float) / mm.getNumberOfLines().(float)) as ratio +from ModuleMetrics mm +where mm.getNumberOfLines() > 0 +select mm, + 100.0 * (mm.getNumberOfLinesOfComments().(float) / mm.getNumberOfLines().(float)) as ratio order by ratio desc diff --git a/python/ql/src/Metrics/CyclomaticComplexity.ql b/python/ql/src/Metrics/CyclomaticComplexity.ql index 1e332f4ec9f..3d9ca10dd99 100644 --- a/python/ql/src/Metrics/CyclomaticComplexity.ql +++ b/python/ql/src/Metrics/CyclomaticComplexity.ql @@ -13,7 +13,8 @@ */ import python +private import LegacyPointsTo -from Function func, int complexity -where complexity = func.getMetrics().getCyclomaticComplexity() +from FunctionMetrics func, int complexity +where complexity = func.getCyclomaticComplexity() select func, complexity order by complexity desc diff --git a/python/ql/src/Metrics/DocStringRatio.ql b/python/ql/src/Metrics/DocStringRatio.ql index a8cd8b8dc4e..824ff5a3509 100644 --- a/python/ql/src/Metrics/DocStringRatio.ql +++ b/python/ql/src/Metrics/DocStringRatio.ql @@ -11,9 +11,10 @@ */ import python +private import LegacyPointsTo -from Module m, ModuleMetrics mm -where mm = m.getMetrics() and mm.getNumberOfLines() > 0 -select m, +from ModuleMetrics mm +where mm.getNumberOfLines() > 0 +select mm, 100.0 * (mm.getNumberOfLinesOfDocStrings().(float) / mm.getNumberOfLines().(float)) as ratio order by ratio desc diff --git a/python/ql/src/Metrics/FLines.ql b/python/ql/src/Metrics/FLines.ql index 340fb6f58ea..dc5418711c9 100644 --- a/python/ql/src/Metrics/FLines.ql +++ b/python/ql/src/Metrics/FLines.ql @@ -9,7 +9,8 @@ */ import python +private import LegacyPointsTo -from Module m, int n -where n = m.getMetrics().getNumberOfLines() +from ModuleMetrics m, int n +where n = m.getNumberOfLines() select m, n order by n desc diff --git a/python/ql/src/Metrics/FLinesOfCode.ql b/python/ql/src/Metrics/FLinesOfCode.ql index 84c952f9267..8159eb86c57 100644 --- a/python/ql/src/Metrics/FLinesOfCode.ql +++ b/python/ql/src/Metrics/FLinesOfCode.ql @@ -11,7 +11,8 @@ */ import python +private import LegacyPointsTo -from Module m, int n -where n = m.getMetrics().getNumberOfLinesOfCode() +from ModuleMetrics m, int n +where n = m.getNumberOfLinesOfCode() select m, n order by n desc diff --git a/python/ql/src/Metrics/FLinesOfComments.ql b/python/ql/src/Metrics/FLinesOfComments.ql index 18a234eef67..ac4b295003a 100644 --- a/python/ql/src/Metrics/FLinesOfComments.ql +++ b/python/ql/src/Metrics/FLinesOfComments.ql @@ -10,8 +10,8 @@ */ import python +private import LegacyPointsTo -from Module m, int n -where - n = m.getMetrics().getNumberOfLinesOfComments() + m.getMetrics().getNumberOfLinesOfDocStrings() +from ModuleMetrics m, int n +where n = m.getNumberOfLinesOfComments() + m.getNumberOfLinesOfDocStrings() select m, n order by n desc diff --git a/python/ql/src/Metrics/FunctionNumberOfCalls.ql b/python/ql/src/Metrics/FunctionNumberOfCalls.ql index fb4dfe5a9d2..60171c790bf 100644 --- a/python/ql/src/Metrics/FunctionNumberOfCalls.ql +++ b/python/ql/src/Metrics/FunctionNumberOfCalls.ql @@ -9,6 +9,7 @@ */ import python +private import LegacyPointsTo from FunctionMetrics func select func, func.getNumberOfCalls() as n order by n desc diff --git a/python/ql/src/Metrics/FunctionStatementNestingDepth.ql b/python/ql/src/Metrics/FunctionStatementNestingDepth.ql index ab40cc6068d..94f7e355750 100644 --- a/python/ql/src/Metrics/FunctionStatementNestingDepth.ql +++ b/python/ql/src/Metrics/FunctionStatementNestingDepth.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from FunctionMetrics func select func, func.getStatementNestingDepth() as n order by n desc diff --git a/python/ql/src/Metrics/History/HChurn.ql b/python/ql/src/Metrics/History/HChurn.ql index d6a8722e6e2..dba28843670 100644 --- a/python/ql/src/Metrics/History/HChurn.ql +++ b/python/ql/src/Metrics/History/HChurn.ql @@ -10,8 +10,9 @@ import python import external.VCS +private import LegacyPointsTo -from Module m, int n +from ModuleMetrics m, int n where n = sum(Commit entry, int churn | @@ -19,5 +20,5 @@ where | churn ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + exists(m.getNumberOfLinesOfCode()) select m, n order by n desc diff --git a/python/ql/src/Metrics/History/HLinesAdded.ql b/python/ql/src/Metrics/History/HLinesAdded.ql index 3ecec917ab1..51a0af62460 100644 --- a/python/ql/src/Metrics/History/HLinesAdded.ql +++ b/python/ql/src/Metrics/History/HLinesAdded.ql @@ -10,8 +10,9 @@ import python import external.VCS +private import LegacyPointsTo -from Module m, int n +from ModuleMetrics m, int n where n = sum(Commit entry, int churn | @@ -19,5 +20,5 @@ where | churn ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + exists(m.getNumberOfLinesOfCode()) select m, n order by n desc diff --git a/python/ql/src/Metrics/History/HLinesDeleted.ql b/python/ql/src/Metrics/History/HLinesDeleted.ql index ded74756d55..3016c9f128b 100644 --- a/python/ql/src/Metrics/History/HLinesDeleted.ql +++ b/python/ql/src/Metrics/History/HLinesDeleted.ql @@ -10,8 +10,9 @@ import python import external.VCS +private import LegacyPointsTo -from Module m, int n +from ModuleMetrics m, int n where n = sum(Commit entry, int churn | @@ -19,5 +20,5 @@ where | churn ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + exists(m.getNumberOfLinesOfCode()) select m, n order by n desc diff --git a/python/ql/src/Metrics/History/HNumberOfAuthors.ql b/python/ql/src/Metrics/History/HNumberOfAuthors.ql index 15e679e58c5..ff00773d98c 100644 --- a/python/ql/src/Metrics/History/HNumberOfAuthors.ql +++ b/python/ql/src/Metrics/History/HNumberOfAuthors.ql @@ -10,7 +10,8 @@ import python import external.VCS +private import LegacyPointsTo -from Module m -where exists(m.getMetrics().getNumberOfLinesOfCode()) +from ModuleMetrics m +where exists(m.getNumberOfLinesOfCode()) select m, count(Author author | author.getAnEditedFile() = m.getFile()) diff --git a/python/ql/src/Metrics/History/HNumberOfCoCommits.ql b/python/ql/src/Metrics/History/HNumberOfCoCommits.ql index afb62353a03..4192ecf57ac 100644 --- a/python/ql/src/Metrics/History/HNumberOfCoCommits.ql +++ b/python/ql/src/Metrics/History/HNumberOfCoCommits.ql @@ -10,11 +10,12 @@ import python import external.VCS +private import LegacyPointsTo int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) } -from Module m -where exists(m.getMetrics().getNumberOfLinesOfCode()) +from ModuleMetrics m +where exists(m.getNumberOfLinesOfCode()) select m, avg(Commit commit, int toAvg | commit.getAnAffectedFile() = m.getFile() and toAvg = committedFiles(commit) - 1 diff --git a/python/ql/src/Metrics/History/HNumberOfReCommits.ql b/python/ql/src/Metrics/History/HNumberOfReCommits.ql index 5df9194ee34..f12c51840dc 100644 --- a/python/ql/src/Metrics/History/HNumberOfReCommits.ql +++ b/python/ql/src/Metrics/History/HNumberOfReCommits.ql @@ -10,6 +10,7 @@ import python import external.VCS +private import LegacyPointsTo predicate inRange(Commit first, Commit second) { first.getAnAffectedFile() = second.getAnAffectedFile() and @@ -29,6 +30,6 @@ int recommitsForFile(File f) { ) } -from Module m -where exists(m.getMetrics().getNumberOfLinesOfCode()) +from ModuleMetrics m +where exists(m.getNumberOfLinesOfCode()) select m, recommitsForFile(m.getFile()) diff --git a/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql b/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql index e04baa491f4..9b787f52957 100644 --- a/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql +++ b/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql @@ -10,9 +10,10 @@ import python import external.VCS +private import LegacyPointsTo -from Module m -where exists(m.getMetrics().getNumberOfLinesOfCode()) +from ModuleMetrics m +where exists(m.getNumberOfLinesOfCode()) select m, count(Author author | exists(Commit e | diff --git a/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql b/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql index f0d8473b302..501094907af 100644 --- a/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql +++ b/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql @@ -10,11 +10,12 @@ import python import external.VCS +private import LegacyPointsTo -from Module m +from ModuleMetrics m where exists(Commit e | e.getAnAffectedFile() = m.getFile() and e.daysToNow() <= 180 and not artificialChange(e) ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + exists(m.getNumberOfLinesOfCode()) select m, 1 diff --git a/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql b/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql index c0ef582c32b..f06b050827c 100644 --- a/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql +++ b/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql @@ -9,6 +9,7 @@ */ import python +private import LegacyPointsTo from ClassMetrics cls select cls, cls.getLackOfCohesionCK() as n order by n desc diff --git a/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql b/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql index 5cc77ecfb4f..1456b76b286 100644 --- a/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql +++ b/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql @@ -9,6 +9,7 @@ */ import python +private import LegacyPointsTo from ClassMetrics cls select cls, cls.getLackOfCohesionHM() as n order by n desc diff --git a/python/ql/src/Metrics/ModuleAfferentCoupling.ql b/python/ql/src/Metrics/ModuleAfferentCoupling.ql index 7bf51433785..d61cc61e4da 100644 --- a/python/ql/src/Metrics/ModuleAfferentCoupling.ql +++ b/python/ql/src/Metrics/ModuleAfferentCoupling.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ModuleMetrics m select m, m.getAfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/ModuleEfferentCoupling.ql b/python/ql/src/Metrics/ModuleEfferentCoupling.ql index 51fdcf5423b..bfabf4b6012 100644 --- a/python/ql/src/Metrics/ModuleEfferentCoupling.ql +++ b/python/ql/src/Metrics/ModuleEfferentCoupling.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from ModuleMetrics m select m, m.getEfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql b/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql index 00a4c1bf0db..e5164499331 100644 --- a/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql +++ b/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql @@ -11,6 +11,7 @@ */ import python +private import LegacyPointsTo from FunctionMetrics func select func, func.getNumberOfParametersWithoutDefault() as n order by n desc diff --git a/python/ql/src/Statements/DocStrings.ql b/python/ql/src/Statements/DocStrings.ql index d7df570a7ef..df7b09a963e 100644 --- a/python/ql/src/Statements/DocStrings.ql +++ b/python/ql/src/Statements/DocStrings.ql @@ -28,12 +28,12 @@ predicate needs_docstring(Scope s) { ) } -predicate function_needs_docstring(Function f) { +predicate function_needs_docstring(FunctionMetrics f) { not exists(FunctionValue fo, FunctionValue base | fo.overrides(base) and fo.getScope() = f | not function_needs_docstring(base.getScope()) ) and f.getName() != "lambda" and - (f.getMetrics().getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and + (f.getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and not exists(PythonPropertyObject p | p.getGetter().getFunction() = f or p.getSetter().getFunction() = f diff --git a/python/ql/src/Summary/LinesOfCode.ql b/python/ql/src/Summary/LinesOfCode.ql index a07a896c4ca..04cb33a3451 100644 --- a/python/ql/src/Summary/LinesOfCode.ql +++ b/python/ql/src/Summary/LinesOfCode.ql @@ -10,5 +10,6 @@ */ import python +private import LegacyPointsTo -select sum(Module m | | m.getMetrics().getNumberOfLinesOfCode()) +select sum(ModuleMetrics m | | m.getNumberOfLinesOfCode()) diff --git a/python/ql/src/Summary/LinesOfUserCode.ql b/python/ql/src/Summary/LinesOfUserCode.ql index f6d6f25872f..f920ebb51f4 100644 --- a/python/ql/src/Summary/LinesOfUserCode.ql +++ b/python/ql/src/Summary/LinesOfUserCode.ql @@ -14,10 +14,11 @@ import python import semmle.python.filters.GeneratedCode +private import LegacyPointsTo -select sum(Module m | +select sum(ModuleMetrics m | exists(m.getFile().getRelativePath()) and not m.getFile() instanceof GeneratedFile | - m.getMetrics().getNumberOfLinesOfCode() + m.getNumberOfLinesOfCode() ) diff --git a/python/ql/src/analysis/Summary.ql b/python/ql/src/analysis/Summary.ql index 630f4e2678b..bad5070a9ef 100644 --- a/python/ql/src/analysis/Summary.ql +++ b/python/ql/src/analysis/Summary.ql @@ -3,6 +3,7 @@ */ import python +private import LegacyPointsTo from string key, string value where diff --git a/python/ql/src/meta/debug/DebugStats.ql b/python/ql/src/meta/debug/DebugStats.ql index 5ebbe963943..03ecaae27e2 100644 --- a/python/ql/src/meta/debug/DebugStats.ql +++ b/python/ql/src/meta/debug/DebugStats.ql @@ -1,15 +1,15 @@ import python +private import LegacyPointsTo from string msg, int cnt, int sort where sort = 0 and msg = "Lines of code in DB" and - cnt = sum(Module m | | m.getMetrics().getNumberOfLinesOfCode()) + cnt = sum(ModuleMetrics m | | m.getNumberOfLinesOfCode()) or sort = 1 and msg = "Lines of code in repo" and - cnt = - sum(Module m | exists(m.getFile().getRelativePath()) | m.getMetrics().getNumberOfLinesOfCode()) + cnt = sum(ModuleMetrics m | exists(m.getFile().getRelativePath()) | m.getNumberOfLinesOfCode()) or sort = 2 and msg = "Files" and diff --git a/python/ql/test/library-tests/ControlFlow/general/Comments.ql b/python/ql/test/library-tests/ControlFlow/general/Comments.ql index 71d00f1a8d4..7fe0545c795 100644 --- a/python/ql/test/library-tests/ControlFlow/general/Comments.ql +++ b/python/ql/test/library-tests/ControlFlow/general/Comments.ql @@ -1,5 +1,6 @@ import python +private import LegacyPointsTo -from Module m, int n -where n = m.getMetrics().getNumberOfLinesOfComments() +from ModuleMetrics m, int n +where n = m.getNumberOfLinesOfComments() select m.toString(), n diff --git a/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql b/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql index fb801a29002..a36375b7f3d 100644 --- a/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql +++ b/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql @@ -1,4 +1,5 @@ import python +private import LegacyPointsTo -from Function func -select func.toString(), func.getMetrics().getCyclomaticComplexity() +from FunctionMetrics func +select func.toString(), func.getCyclomaticComplexity() diff --git a/python/ql/test/library-tests/ControlFlow/general/Lines.ql b/python/ql/test/library-tests/ControlFlow/general/Lines.ql index ca6e7715538..2e861691fbb 100644 --- a/python/ql/test/library-tests/ControlFlow/general/Lines.ql +++ b/python/ql/test/library-tests/ControlFlow/general/Lines.ql @@ -1,8 +1,9 @@ import python +private import LegacyPointsTo from Scope s, int n where - exists(Function f | f = s | n = f.getMetrics().getNumberOfLines()) + exists(FunctionMetrics f | f = s | n = f.getNumberOfLines()) or - exists(Module m | m = s | n = m.getMetrics().getNumberOfLines()) + exists(ModuleMetrics m | m = s | n = m.getNumberOfLines()) select s.toString(), n diff --git a/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql index 745568f2405..a5c563b1123 100644 --- a/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql +++ b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql @@ -1,6 +1,7 @@ import python +private import LegacyPointsTo -from Module m, ModuleMetrics mm -where mm = m.getMetrics() and mm.getNumberOfLines() > 0 -select m, 100.0 * (mm.getNumberOfLinesOfCode().(float) / mm.getNumberOfLines().(float)) as ratio +from ModuleMetrics mm +where mm.getNumberOfLines() > 0 +select mm, 100.0 * (mm.getNumberOfLinesOfCode().(float) / mm.getNumberOfLines().(float)) as ratio order by ratio desc From c6ad438bfcff5652d4769cf01d81c0ad1857e9a7 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 26 Nov 2025 21:58:26 +0000 Subject: [PATCH 19/22] Python: Add change note --- .../2025-11-26-remove-top-level-points-to-import.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md diff --git a/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md b/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md new file mode 100644 index 00000000000..eb096c0b97f --- /dev/null +++ b/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md @@ -0,0 +1,7 @@ +--- +category: breaking +--- + +- All modules that depend on the points-to analysis have now been removed from the top level `python.qll` module. To access the points-to functionality, import the new `LegacyPointsTo` module. This also means that some predicates have been removed from various classes, for instance `Function.getFunctionObject()`. To access these predicates, import the `LegacyPointsTo` module and use the `FunctionWithPointsTo` class instead. Most cases follow this pattern, but there are a few exceptions: + - The `getLiteralObject` method on `ImmutableLiteral` subclasses has been replaced with a predicate `getLiteralObject(ImmutableLiteral l)` in the `LegacyPointsTo` module. + - The `getMetrics` method on `Function`, `Class`, and `Module` has been removed. To access metrics, import `LegacyPointsTo` and use the classes `FunctionMetrics`, etc. instead. From a7458df0a4835cbc74de56e55831e4f7417f353b Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 26 Nov 2025 22:13:21 +0000 Subject: [PATCH 20/22] Python: Appease the QLDoc checker --- python/ql/lib/LegacyPointsTo.qll | 1 + python/ql/lib/semmle/python/Exprs.qll | 1 + python/ql/lib/semmle/python/types/Exceptions.qll | 1 + 3 files changed, 3 insertions(+) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index c5821f3d009..45f4a80e8d1 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -299,6 +299,7 @@ class ClassWithPointsTo extends Class { override string getAQlClass() { none() } } +/** Gets the `Object` corresponding to the immutable literal `l`. */ Object getLiteralObject(ImmutableLiteral l) { l instanceof IntegerLiteral and ( diff --git a/python/ql/lib/semmle/python/Exprs.qll b/python/ql/lib/semmle/python/Exprs.qll index 203e63f611f..c374863d684 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -565,6 +565,7 @@ class StringLiteral extends Str_, ImmutableLiteral { override string toString() { result = "StringLiteral" } } +/** Holds if `n` is a named constant (`True`, `False`, or `None`) with name `id`. */ predicate name_consts(Name_ n, string id) { exists(Variable v | py_variables(v, n) and id = v.getId() | id = "True" or id = "False" or id = "None" diff --git a/python/ql/lib/semmle/python/types/Exceptions.qll b/python/ql/lib/semmle/python/types/Exceptions.qll index dd9ee1703a6..ea2f20e67aa 100644 --- a/python/ql/lib/semmle/python/types/Exceptions.qll +++ b/python/ql/lib/semmle/python/types/Exceptions.qll @@ -368,6 +368,7 @@ predicate scope_raises_unknown(Scope s) { ) } +/** An extension of `ExceptFlowNode` that provides points-to related methods. */ class ExceptFlowNodeWithPointsTo extends ExceptFlowNode { private predicate handledObject_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) { this.getType().(ControlFlowNodeWithPointsTo).refersTo(obj, cls, origin) From bc8ed286ac2f8f4ef4505a1636fc26562e984996 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 27 Nov 2025 16:47:53 +0000 Subject: [PATCH 21/22] Python: Make some more points-to imports private This makes things a bit cleaner. After this, the only non-private (and non-`LegacyPointsTo`) imports of `semmle.python.{types,objects,pointsto}.*` are in `semmle.python.objects.ObjectInternal`, which is reasonable, as that is the entry point for the entire internal object API. --- python/ql/lib/semmle/python/pointsto/PointsTo.qll | 1 + python/ql/lib/semmle/python/types/Extensions.qll | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/pointsto/PointsTo.qll b/python/ql/lib/semmle/python/pointsto/PointsTo.qll index ce1485c3f3d..66b82367de0 100644 --- a/python/ql/lib/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/lib/semmle/python/pointsto/PointsTo.qll @@ -6,6 +6,7 @@ private import semmle.python.pointsto.PointsToContext private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins private import semmle.python.types.Extensions +private import semmle.python.pointsto.Context private import semmle.python.internal.CachedStages private import semmle.python.types.Object private import semmle.python.types.FunctionObject diff --git a/python/ql/lib/semmle/python/types/Extensions.qll b/python/ql/lib/semmle/python/types/Extensions.qll index d292f568fb9..3cde11977d0 100644 --- a/python/ql/lib/semmle/python/types/Extensions.qll +++ b/python/ql/lib/semmle/python/types/Extensions.qll @@ -15,8 +15,8 @@ private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.PointsToContext private import semmle.python.objects.TObject /* Make ObjectInternal visible to save extra imports in user code */ -import semmle.python.objects.ObjectInternal -import semmle.python.pointsto.Context +private import semmle.python.objects.ObjectInternal +private import semmle.python.pointsto.Context abstract class PointsToExtension extends @py_flow_node { string toString() { result = "PointsToExtension with missing toString" } From ec336a0334009a4a28aebcb7e46faa008dc3eb63 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 27 Nov 2025 17:49:13 +0100 Subject: [PATCH 22/22] Python: Fix list bullets in change note Co-authored-by: Mathias Vorreiter Pedersen --- .../2025-11-26-remove-top-level-points-to-import.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md b/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md index eb096c0b97f..7122c217c41 100644 --- a/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md +++ b/python/ql/lib/change-notes/2025-11-26-remove-top-level-points-to-import.md @@ -2,6 +2,6 @@ category: breaking --- -- All modules that depend on the points-to analysis have now been removed from the top level `python.qll` module. To access the points-to functionality, import the new `LegacyPointsTo` module. This also means that some predicates have been removed from various classes, for instance `Function.getFunctionObject()`. To access these predicates, import the `LegacyPointsTo` module and use the `FunctionWithPointsTo` class instead. Most cases follow this pattern, but there are a few exceptions: - - The `getLiteralObject` method on `ImmutableLiteral` subclasses has been replaced with a predicate `getLiteralObject(ImmutableLiteral l)` in the `LegacyPointsTo` module. - - The `getMetrics` method on `Function`, `Class`, and `Module` has been removed. To access metrics, import `LegacyPointsTo` and use the classes `FunctionMetrics`, etc. instead. +* All modules that depend on the points-to analysis have now been removed from the top level `python.qll` module. To access the points-to functionality, import the new `LegacyPointsTo` module. This also means that some predicates have been removed from various classes, for instance `Function.getFunctionObject()`. To access these predicates, import the `LegacyPointsTo` module and use the `FunctionWithPointsTo` class instead. Most cases follow this pattern, but there are a few exceptions: + * The `getLiteralObject` method on `ImmutableLiteral` subclasses has been replaced with a predicate `getLiteralObject(ImmutableLiteral l)` in the `LegacyPointsTo` module. + * The `getMetrics` method on `Function`, `Class`, and `Module` has been removed. To access metrics, import `LegacyPointsTo` and use the classes `FunctionMetrics`, etc. instead.