@@ -17,13 +17,15 @@ use num_traits::ToPrimitive;
1717use pyrefly_build:: handle:: Handle ;
1818use pyrefly_python:: ast:: Ast ;
1919use pyrefly_python:: docstring:: Docstring ;
20+ use pyrefly_python:: dunder;
2021use pyrefly_python:: module_name:: ModuleName ;
2122use pyrefly_util:: visit:: Visit ;
2223use ruff_python_ast:: Decorator ;
2324use ruff_python_ast:: ExceptHandler ;
2425use ruff_python_ast:: Expr ;
2526use ruff_python_ast:: ExprAttribute ;
2627use ruff_python_ast:: ExprCall ;
28+ use ruff_python_ast:: ExprList ;
2729use ruff_python_ast:: ExprName ;
2830use ruff_python_ast:: ExprStringLiteral ;
2931use ruff_python_ast:: Identifier ;
@@ -168,6 +170,13 @@ struct GleanState<'a> {
168170 facts : Facts ,
169171 names : HashSet < Arc < String > > ,
170172 locations_fqnames : HashMap < TextSize , Arc < String > > ,
173+ import_names : HashMap < Arc < String > , Arc < String > > ,
174+ }
175+
176+ struct AssignInfo < ' a > {
177+ range : TextRange ,
178+ annotation : Option < & ' a Expr > ,
179+ value : Option < & ' a Expr > ,
171180}
172181
173182impl Facts {
@@ -204,6 +213,7 @@ impl GleanState<'_> {
204213 ) ,
205214 names : HashSet :: new ( ) ,
206215 locations_fqnames : HashMap :: new ( ) ,
216+ import_names : HashMap :: new ( ) ,
207217 }
208218 }
209219
@@ -231,7 +241,7 @@ impl GleanState<'_> {
231241 let name = module. map_or ( ModuleName :: from_name ( & component) , |x : ModuleName | {
232242 x. append ( & component)
233243 } ) ;
234- self . record_name ( name. to_string ( ) , None ) ;
244+ self . record_name ( name. to_string ( ) ) ;
235245 module = Some ( name) ;
236246 module_names. push ( name) ;
237247 }
@@ -248,7 +258,7 @@ impl GleanState<'_> {
248258 let name = module. map_or ( ModuleName :: from_name ( & component) , |x : ModuleName | {
249259 x. append ( & component)
250260 } ) ;
251- self . record_name ( name. to_string ( ) , None ) ;
261+ self . record_name ( name. to_string ( ) ) ;
252262 self . facts
253263 . modules
254264 . push ( python:: Module :: new ( python:: Name :: new ( name. to_string ( ) ) ) ) ;
@@ -321,19 +331,29 @@ impl GleanState<'_> {
321331 }
322332 }
323333
324- fn record_name ( & mut self , name : String , position : Option < TextSize > ) -> python :: Name {
334+ fn record_name ( & mut self , name : String ) -> Arc < String > {
325335 let arc_name = Arc :: new ( name. clone ( ) ) ;
326336 if self . names . insert ( arc_name. dupe ( ) ) {
327337 self . facts . name_to_sname . push ( python:: NameToSName :: new (
328338 python:: Name :: new ( name. clone ( ) ) ,
329339 create_sname ( & name) ,
330340 ) ) ;
331341 }
332- position. map ( |x| self . locations_fqnames . insert ( x, arc_name. dupe ( ) ) ) ;
342+ arc_name
343+ }
333344
345+ fn record_name_with_position ( & mut self , name : String , position : TextSize ) -> python:: Name {
346+ let arc_name = self . record_name ( name. clone ( ) ) ;
347+ self . locations_fqnames . insert ( position, arc_name. dupe ( ) ) ;
334348 python:: Name :: new ( name)
335349 }
336350
351+ fn record_name_for_import ( & mut self , name : String , import_name : & str ) {
352+ let arc_name = self . record_name ( name) ;
353+ let arc_import_name = Arc :: new ( import_name. to_owned ( ) ) ;
354+ self . import_names . insert ( arc_name. dupe ( ) , arc_import_name) ;
355+ }
356+
337357 fn make_fq_name_for_declaration (
338358 & mut self ,
339359 name : & Identifier ,
@@ -362,9 +382,9 @@ impl GleanState<'_> {
362382 }
363383 } ;
364384 if !self . names . contains ( & scope) {
365- self . record_name ( scope. clone ( ) , None ) ;
385+ self . record_name ( scope. clone ( ) ) ;
366386 }
367- self . record_name ( join_names ( & scope, name) , Some ( name. range . start ( ) ) )
387+ self . record_name_with_position ( join_names ( & scope, name) , name. range . start ( ) )
368388 }
369389
370390 fn make_fq_names_for_expr ( & self , expr : & Expr ) -> Vec < python:: Name > {
@@ -806,11 +826,33 @@ impl GleanState<'_> {
806826 decl_infos
807827 }
808828
829+ fn add_xrefs_for_explicit_exports ( & mut self , exprs_list : & [ Expr ] ) {
830+ let exports = exprs_list
831+ . iter ( )
832+ . filter_map ( |e| e. as_string_literal_expr ( ) )
833+ . map ( |str_lit| ( str_lit. value . to_str ( ) , str_lit. range ( ) ) ) ;
834+
835+ for ( local_name, source) in exports {
836+ let name = join_names ( self . module_name . as_str ( ) , local_name) ;
837+ if self . names . contains ( & name) {
838+ let fqname = self
839+ . import_names
840+ . get ( & name)
841+ . map ( |n| ( * * n) . clone ( ) )
842+ . unwrap_or ( name) ;
843+
844+ self . add_xref ( python:: XRefViaName {
845+ target : python:: Name :: new ( fqname) ,
846+ source : to_span ( source) ,
847+ } ) ;
848+ }
849+ }
850+ }
851+
809852 fn variable_facts (
810853 & mut self ,
811854 expr : & Expr ,
812- range : TextRange ,
813- annotation : Option < & Expr > ,
855+ info : & AssignInfo ,
814856 ctx : & NodeContext ,
815857 next : Option < & Stmt > ,
816858 def_infos : & mut Vec < DeclarationInfo > ,
@@ -830,15 +872,20 @@ impl GleanState<'_> {
830872 next. and_then ( |stmt| Docstring :: range_from_stmts ( slice:: from_ref ( stmt) ) ) ;
831873 def_infos. push ( self . variable_info (
832874 fqname,
833- range,
834- self . type_info ( annotation) ,
875+ info . range ,
876+ self . type_info ( info . annotation ) ,
835877 docstring_range,
836878 ctx,
837879 ) ) ;
880+
881+ if name. id ( ) == & dunder:: ALL
882+ && let Some ( value) = info. value
883+ && let Expr :: List ( ExprList { elts, .. } ) = value
884+ {
885+ self . add_xrefs_for_explicit_exports ( elts) ;
886+ }
838887 }
839- expr. recurse ( & mut |expr| {
840- self . variable_facts ( expr, range, annotation, ctx, next, def_infos)
841- } ) ;
888+ expr. recurse ( & mut |expr| self . variable_facts ( expr, info, ctx, next, def_infos) ) ;
842889 }
843890
844891 fn find_fqname_definition_at_position ( & self , position : TextSize ) -> Vec < String > {
@@ -862,12 +909,8 @@ impl GleanState<'_> {
862909 resolve_original_name : bool ,
863910 ) -> DeclarationInfo {
864911 let as_name_fqname = join_names ( self . module_name . as_str ( ) , as_name) ;
865- self . record_name ( from_name. to_owned ( ) , Some ( as_name_range. start ( ) ) ) ;
866- self . record_name ( as_name_fqname. clone ( ) , None ) ;
867-
868912 let from_name_fact = python:: Name :: new ( from_name. to_owned ( ) ) ;
869- let as_name_fact = python:: Name :: new ( as_name_fqname) ;
870-
913+ let as_name_fact = python:: Name :: new ( as_name_fqname. clone ( ) ) ;
871914 let original_name = if resolve_original_name
872915 && let Some ( name) = self
873916 . find_fqname_definition_at_position ( from_name_range. start ( ) )
@@ -877,6 +920,9 @@ impl GleanState<'_> {
877920 } else {
878921 from_name. to_owned ( )
879922 } ;
923+
924+ self . record_name_with_position ( from_name. to_owned ( ) , as_name_range. start ( ) ) ;
925+ self . record_name_for_import ( as_name_fqname, & original_name) ;
880926 self . add_xref ( python:: XRefViaName {
881927 target : python:: Name :: new ( original_name) ,
882928 source : to_span ( from_name_range) ,
@@ -1161,39 +1207,33 @@ impl GleanState<'_> {
11611207 decl_infos. append ( & mut func_decl_infos) ;
11621208 }
11631209 Stmt :: Assign ( assign) => {
1210+ let info = AssignInfo {
1211+ range : assign. range ( ) ,
1212+ annotation : None ,
1213+ value : Some ( assign. value . as_ref ( ) ) ,
1214+ } ;
11641215 assign. targets . visit ( & mut |target| {
1165- self . variable_facts (
1166- target,
1167- assign. range ( ) ,
1168- None ,
1169- context,
1170- next,
1171- & mut decl_infos,
1172- )
1216+ self . variable_facts ( target, & info, context, next, & mut decl_infos)
11731217 } ) ;
11741218 self . visit_exprs ( & assign. value , container) ;
11751219 }
11761220 Stmt :: AnnAssign ( assign) => {
1177- self . variable_facts (
1178- & assign. target ,
1179- assign. range ( ) ,
1180- Some ( & assign. annotation ) ,
1181- context,
1182- next,
1183- & mut decl_infos,
1184- ) ;
1221+ let info = AssignInfo {
1222+ range : assign. range ( ) ,
1223+ annotation : Some ( & assign. annotation ) ,
1224+ value : assign. value . as_ref ( ) . map ( |v| v. as_ref ( ) ) ,
1225+ } ;
1226+ self . variable_facts ( & assign. target , & info, context, next, & mut decl_infos) ;
11851227 self . visit_exprs ( & assign. annotation , container) ;
11861228 self . visit_exprs ( & assign. value , container) ;
11871229 }
11881230 Stmt :: AugAssign ( assign) => {
1189- self . variable_facts (
1190- & assign. target ,
1191- assign. range ( ) ,
1192- None ,
1193- context,
1194- next,
1195- & mut decl_infos,
1196- ) ;
1231+ let info = AssignInfo {
1232+ range : assign. range ( ) ,
1233+ annotation : None ,
1234+ value : Some ( assign. value . as_ref ( ) ) ,
1235+ } ;
1236+ self . variable_facts ( & assign. target , & info, context, next, & mut decl_infos) ;
11971237 self . visit_exprs ( & assign. value , container) ;
11981238 }
11991239 Stmt :: Import ( import) => {
@@ -1206,14 +1246,12 @@ impl GleanState<'_> {
12061246 }
12071247 Stmt :: For ( stmt_for) => {
12081248 stmt_for. target . visit ( & mut |target| {
1209- self . variable_facts (
1210- target,
1211- target. range ( ) ,
1212- None ,
1213- context,
1214- next,
1215- & mut decl_infos,
1216- )
1249+ let info = AssignInfo {
1250+ range : target. range ( ) ,
1251+ annotation : None ,
1252+ value : None ,
1253+ } ;
1254+ self . variable_facts ( target, & info, context, next, & mut decl_infos)
12171255 } ) ;
12181256 self . visit_exprs ( & stmt_for. iter , container) ;
12191257 }
@@ -1228,14 +1266,12 @@ impl GleanState<'_> {
12281266 for item in & stmt_with. items {
12291267 self . visit_exprs ( & item. context_expr , container) ;
12301268 item. optional_vars . visit ( & mut |target| {
1231- self . variable_facts (
1232- target,
1233- target. range ( ) ,
1234- None ,
1235- context,
1236- next,
1237- & mut decl_infos,
1238- )
1269+ let info = AssignInfo {
1270+ range : target. range ( ) ,
1271+ annotation : None ,
1272+ value : None ,
1273+ } ;
1274+ self . variable_facts ( target, & info, context, next, & mut decl_infos)
12391275 } ) ;
12401276 }
12411277 }
@@ -1281,7 +1317,7 @@ impl Glean {
12811317 let ast = & * transaction. get_ast ( handle) . unwrap ( ) ;
12821318 let mut glean_state = GleanState :: new ( transaction, handle) ;
12831319
1284- glean_state. record_name ( "" . to_owned ( ) , None ) ;
1320+ glean_state. record_name ( "" . to_owned ( ) ) ;
12851321 let file_language_fact =
12861322 src:: FileLanguage :: new ( glean_state. file_fact ( ) , src:: Language :: Python ) ;
12871323 let digest_fact = glean_state. digest_fact ( ) ;
0 commit comments