@@ -52,14 +52,13 @@ use ruff_python_parser::typing::{parse_type_annotation, AnnotationKind};
52
52
use ruff_python_semantic:: analyze:: { imports, typing, visibility} ;
53
53
use ruff_python_semantic:: {
54
54
BindingFlags , BindingId , BindingKind , Exceptions , Export , FromImport , Globals , Import , Module ,
55
- ModuleKind , NodeId , ScopeId , ScopeKind , SemanticModel , SemanticModelFlags , Snapshot ,
56
- StarImport , SubmoduleImport ,
55
+ ModuleKind , NodeId , ScopeId , ScopeKind , SemanticModel , SemanticModelFlags , StarImport ,
56
+ SubmoduleImport ,
57
57
} ;
58
58
use ruff_python_stdlib:: builtins:: { IPYTHON_BUILTINS , MAGIC_GLOBALS , PYTHON_BUILTINS } ;
59
59
use ruff_source_file:: { Locator , OneIndexed , SourceRow } ;
60
60
61
61
use crate :: checkers:: ast:: annotation:: AnnotationContext ;
62
- use crate :: checkers:: ast:: deferred:: Deferred ;
63
62
use crate :: docstrings:: extraction:: ExtractionTarget ;
64
63
use crate :: importer:: Importer ;
65
64
use crate :: noqa:: NoqaMapping ;
@@ -105,8 +104,10 @@ pub(crate) struct Checker<'a> {
105
104
importer : Importer < ' a > ,
106
105
/// The [`SemanticModel`], built up over the course of the AST traversal.
107
106
semantic : SemanticModel < ' a > ,
108
- /// A set of deferred nodes to be processed after the current traversal (e.g., function bodies).
109
- deferred : Deferred < ' a > ,
107
+ /// A set of deferred nodes to be visited after the current traversal (e.g., function bodies).
108
+ visit : deferred:: Visit < ' a > ,
109
+ /// A set of deferred nodes to be analyzed after the AST traversal (e.g., `for` loops).
110
+ analyze : deferred:: Analyze ,
110
111
/// The cumulative set of diagnostics computed across all lint rules.
111
112
pub ( crate ) diagnostics : Vec < Diagnostic > ,
112
113
/// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations..
@@ -145,7 +146,8 @@ impl<'a> Checker<'a> {
145
146
indexer,
146
147
importer,
147
148
semantic : SemanticModel :: new ( & settings. typing_modules , path, module) ,
148
- deferred : Deferred :: default ( ) ,
149
+ visit : deferred:: Visit :: default ( ) ,
150
+ analyze : deferred:: Analyze :: default ( ) ,
149
151
diagnostics : Vec :: default ( ) ,
150
152
flake8_bugbear_seen : Vec :: default ( ) ,
151
153
cell_offsets,
@@ -596,7 +598,7 @@ where
596
598
self . semantic . push_scope ( ScopeKind :: Function ( function_def) ) ;
597
599
self . semantic . flags -= SemanticModelFlags :: EXCEPTION_HANDLER ;
598
600
599
- self . deferred . functions . push ( self . semantic . snapshot ( ) ) ;
601
+ self . visit . functions . push ( self . semantic . snapshot ( ) ) ;
600
602
601
603
// Extract any global bindings from the function body.
602
604
if let Some ( globals) = Globals :: from_body ( body) {
@@ -652,7 +654,7 @@ where
652
654
if let Some ( type_params) = type_params {
653
655
self . visit_type_params ( type_params) ;
654
656
}
655
- self . deferred
657
+ self . visit
656
658
. type_param_definitions
657
659
. push ( ( value, self . semantic . snapshot ( ) ) ) ;
658
660
self . semantic . pop_scope ( ) ;
@@ -785,7 +787,7 @@ where
785
787
match stmt {
786
788
Stmt :: FunctionDef ( ast:: StmtFunctionDef { name, .. } ) => {
787
789
let scope_id = self . semantic . scope_id ;
788
- self . deferred . scopes . push ( scope_id) ;
790
+ self . analyze . scopes . push ( scope_id) ;
789
791
self . semantic . pop_scope ( ) ; // Function scope
790
792
self . semantic . pop_definition ( ) ;
791
793
self . semantic . pop_scope ( ) ; // Type parameter scope
@@ -798,7 +800,7 @@ where
798
800
}
799
801
Stmt :: ClassDef ( ast:: StmtClassDef { name, .. } ) => {
800
802
let scope_id = self . semantic . scope_id ;
801
- self . deferred . scopes . push ( scope_id) ;
803
+ self . analyze . scopes . push ( scope_id) ;
802
804
self . semantic . pop_scope ( ) ; // Class scope
803
805
self . semantic . pop_definition ( ) ;
804
806
self . semantic . pop_scope ( ) ; // Type parameter scope
@@ -835,13 +837,13 @@ where
835
837
&& self . semantic . future_annotations ( )
836
838
{
837
839
if let Expr :: StringLiteral ( ast:: ExprStringLiteral { value, .. } ) = expr {
838
- self . deferred . string_type_definitions . push ( (
840
+ self . visit . string_type_definitions . push ( (
839
841
expr. range ( ) ,
840
842
value. to_str ( ) ,
841
843
self . semantic . snapshot ( ) ,
842
844
) ) ;
843
845
} else {
844
- self . deferred
846
+ self . visit
845
847
. future_type_definitions
846
848
. push ( ( expr, self . semantic . snapshot ( ) ) ) ;
847
849
}
@@ -945,7 +947,8 @@ where
945
947
}
946
948
947
949
self . semantic . push_scope ( ScopeKind :: Lambda ( lambda) ) ;
948
- self . deferred . lambdas . push ( self . semantic . snapshot ( ) ) ;
950
+ self . visit . lambdas . push ( self . semantic . snapshot ( ) ) ;
951
+ self . analyze . lambdas . push ( self . semantic . snapshot ( ) ) ;
949
952
}
950
953
Expr :: IfExp ( ast:: ExprIfExp {
951
954
test,
@@ -1252,7 +1255,7 @@ where
1252
1255
}
1253
1256
Expr :: StringLiteral ( ast:: ExprStringLiteral { value, .. } ) => {
1254
1257
if self . semantic . in_type_definition ( ) && !self . semantic . in_typing_literal ( ) {
1255
- self . deferred . string_type_definitions . push ( (
1258
+ self . visit . string_type_definitions . push ( (
1256
1259
expr. range ( ) ,
1257
1260
value. to_str ( ) ,
1258
1261
self . semantic . snapshot ( ) ,
@@ -1273,7 +1276,7 @@ where
1273
1276
| Expr :: ListComp ( _)
1274
1277
| Expr :: DictComp ( _)
1275
1278
| Expr :: SetComp ( _) => {
1276
- self . deferred . scopes . push ( self . semantic . scope_id ) ;
1279
+ self . analyze . scopes . push ( self . semantic . scope_id ) ;
1277
1280
self . semantic . pop_scope ( ) ;
1278
1281
}
1279
1282
_ => { }
@@ -1447,7 +1450,7 @@ where
1447
1450
bound : Some ( bound) , ..
1448
1451
} ) = type_param
1449
1452
{
1450
- self . deferred
1453
+ self . visit
1451
1454
. type_param_definitions
1452
1455
. push ( ( bound, self . semantic . snapshot ( ) ) ) ;
1453
1456
}
@@ -1809,8 +1812,8 @@ impl<'a> Checker<'a> {
1809
1812
1810
1813
fn visit_deferred_future_type_definitions ( & mut self ) {
1811
1814
let snapshot = self . semantic . snapshot ( ) ;
1812
- while !self . deferred . future_type_definitions . is_empty ( ) {
1813
- let type_definitions = std:: mem:: take ( & mut self . deferred . future_type_definitions ) ;
1815
+ while !self . visit . future_type_definitions . is_empty ( ) {
1816
+ let type_definitions = std:: mem:: take ( & mut self . visit . future_type_definitions ) ;
1814
1817
for ( expr, snapshot) in type_definitions {
1815
1818
self . semantic . restore ( snapshot) ;
1816
1819
@@ -1824,8 +1827,8 @@ impl<'a> Checker<'a> {
1824
1827
1825
1828
fn visit_deferred_type_param_definitions ( & mut self ) {
1826
1829
let snapshot = self . semantic . snapshot ( ) ;
1827
- while !self . deferred . type_param_definitions . is_empty ( ) {
1828
- let type_params = std:: mem:: take ( & mut self . deferred . type_param_definitions ) ;
1830
+ while !self . visit . type_param_definitions . is_empty ( ) {
1831
+ let type_params = std:: mem:: take ( & mut self . visit . type_param_definitions ) ;
1829
1832
for ( type_param, snapshot) in type_params {
1830
1833
self . semantic . restore ( snapshot) ;
1831
1834
@@ -1839,8 +1842,8 @@ impl<'a> Checker<'a> {
1839
1842
1840
1843
fn visit_deferred_string_type_definitions ( & mut self , allocator : & ' a typed_arena:: Arena < Expr > ) {
1841
1844
let snapshot = self . semantic . snapshot ( ) ;
1842
- while !self . deferred . string_type_definitions . is_empty ( ) {
1843
- let type_definitions = std:: mem:: take ( & mut self . deferred . string_type_definitions ) ;
1845
+ while !self . visit . string_type_definitions . is_empty ( ) {
1846
+ let type_definitions = std:: mem:: take ( & mut self . visit . string_type_definitions ) ;
1844
1847
for ( range, value, snapshot) in type_definitions {
1845
1848
if let Ok ( ( expr, kind) ) =
1846
1849
parse_type_annotation ( value, range, self . locator . contents ( ) )
@@ -1887,8 +1890,8 @@ impl<'a> Checker<'a> {
1887
1890
1888
1891
fn visit_deferred_functions ( & mut self ) {
1889
1892
let snapshot = self . semantic . snapshot ( ) ;
1890
- while !self . deferred . functions . is_empty ( ) {
1891
- let deferred_functions = std:: mem:: take ( & mut self . deferred . functions ) ;
1893
+ while !self . visit . functions . is_empty ( ) {
1894
+ let deferred_functions = std:: mem:: take ( & mut self . visit . functions ) ;
1892
1895
for snapshot in deferred_functions {
1893
1896
self . semantic . restore ( snapshot) ;
1894
1897
@@ -1906,11 +1909,12 @@ impl<'a> Checker<'a> {
1906
1909
self . semantic . restore ( snapshot) ;
1907
1910
}
1908
1911
1912
+ /// Visit all deferred lambdas. Returns a list of snapshots, such that the caller can restore
1913
+ /// the semantic model to the state it was in before visiting the deferred lambdas.
1909
1914
fn visit_deferred_lambdas ( & mut self ) {
1910
1915
let snapshot = self . semantic . snapshot ( ) ;
1911
- let mut deferred: Vec < Snapshot > = Vec :: with_capacity ( self . deferred . lambdas . len ( ) ) ;
1912
- while !self . deferred . lambdas . is_empty ( ) {
1913
- let lambdas = std:: mem:: take ( & mut self . deferred . lambdas ) ;
1916
+ while !self . visit . lambdas . is_empty ( ) {
1917
+ let lambdas = std:: mem:: take ( & mut self . visit . lambdas ) ;
1914
1918
for snapshot in lambdas {
1915
1919
self . semantic . restore ( snapshot) ;
1916
1920
@@ -1927,15 +1931,23 @@ impl<'a> Checker<'a> {
1927
1931
self . visit_parameters ( parameters) ;
1928
1932
}
1929
1933
self . visit_expr ( body) ;
1930
-
1931
- deferred. push ( snapshot) ;
1932
1934
}
1933
1935
}
1934
- // Reset the deferred lambdas, so we can analyze them later on.
1935
- self . deferred . lambdas = deferred;
1936
1936
self . semantic . restore ( snapshot) ;
1937
1937
}
1938
1938
1939
+ /// Recursively visit all deferred AST nodes, including lambdas, functions, and type
1940
+ /// annotations.
1941
+ fn visit_deferred ( & mut self , allocator : & ' a typed_arena:: Arena < Expr > ) {
1942
+ while !self . visit . is_empty ( ) {
1943
+ self . visit_deferred_functions ( ) ;
1944
+ self . visit_deferred_type_param_definitions ( ) ;
1945
+ self . visit_deferred_lambdas ( ) ;
1946
+ self . visit_deferred_future_type_definitions ( ) ;
1947
+ self . visit_deferred_string_type_definitions ( allocator) ;
1948
+ }
1949
+ }
1950
+
1939
1951
/// Run any lint rules that operate over the module exports (i.e., members of `__all__`).
1940
1952
fn visit_exports ( & mut self ) {
1941
1953
let snapshot = self . semantic . snapshot ( ) ;
@@ -2043,12 +2055,8 @@ pub(crate) fn check_ast(
2043
2055
// Visit any deferred syntax nodes. Take care to visit in order, such that we avoid adding
2044
2056
// new deferred nodes after visiting nodes of that kind. For example, visiting a deferred
2045
2057
// function can add a deferred lambda, but the opposite is not true.
2046
- checker. visit_deferred_functions ( ) ;
2047
- checker. visit_deferred_type_param_definitions ( ) ;
2048
- checker. visit_deferred_lambdas ( ) ;
2049
- checker. visit_deferred_future_type_definitions ( ) ;
2050
2058
let allocator = typed_arena:: Arena :: new ( ) ;
2051
- checker. visit_deferred_string_type_definitions ( & allocator) ;
2059
+ checker. visit_deferred ( & allocator) ;
2052
2060
checker. visit_exports ( ) ;
2053
2061
2054
2062
// Check docstrings, bindings, and unresolved references.
@@ -2060,7 +2068,7 @@ pub(crate) fn check_ast(
2060
2068
2061
2069
// Reset the scope to module-level, and check all consumed scopes.
2062
2070
checker. semantic . scope_id = ScopeId :: global ( ) ;
2063
- checker. deferred . scopes . push ( ScopeId :: global ( ) ) ;
2071
+ checker. analyze . scopes . push ( ScopeId :: global ( ) ) ;
2064
2072
analyze:: deferred_scopes ( & mut checker) ;
2065
2073
2066
2074
checker. diagnostics
0 commit comments