@@ -126,6 +126,14 @@ class NamespaceData:
126126 # --- ScopeTree (local scopes only, file_scope is reconstructed) ---
127127 local_scopes : List [LocalScope ] = field (default_factory = list )
128128
129+ # --- Authoritative variable definitions (stable_id → VariableDefinition) ---
130+ # Stores the exact VariableDefinition objects that were referenced during
131+ # analysis. Used as fallback in from_data() when the re-parsed resource doc
132+ # produces variables with different stable_ids (e.g. col_offset differences
133+ # for variables with '=' suffix, or keyword argument definitions from
134+ # imported keywords that aren't in the file's own scope).
135+ variable_definitions : Dict [str , VariableDefinition ] = field (default_factory = dict )
136+
129137
130138class Namespace :
131139 """Data container holding all results of a namespace build.
@@ -450,6 +458,42 @@ def to_data(self) -> NamespaceData:
450458 key = f"{ type (entry ).__name__ } :{ entry .import_name } :{ entry .args !r} :{ entry .alias or '' } "
451459 ns_refs [key ] = locs
452460
461+ # Collect all referenced variable definitions for stable_id → object lookup
462+ all_var_defs : Dict [str , VariableDefinition ] = {}
463+ for var in self ._variable_references :
464+ all_var_defs [var .stable_id ] = var
465+ for var in self ._local_variable_assignments :
466+ all_var_defs [var .stable_id ] = var
467+
468+ # Build keyword_references merging locations when different KeywordDoc
469+ # objects share the same stable_id (e.g. same library imported with
470+ # different aliases like "errorlib" and "noerrorlib").
471+ kw_refs_merged : Dict [str , Set [Location ]] = {}
472+ for kw , locs in self ._keyword_references .items ():
473+ sid = kw .stable_id
474+ if sid in kw_refs_merged :
475+ kw_refs_merged [sid ].update (locs )
476+ else :
477+ kw_refs_merged [sid ] = set (locs )
478+
479+ # Same merge for variable_references (different VariableDefinition
480+ # objects could theoretically share a stable_id).
481+ var_refs_merged : Dict [str , Set [Location ]] = {}
482+ for var , locs in self ._variable_references .items ():
483+ sid = var .stable_id
484+ if sid in var_refs_merged :
485+ var_refs_merged [sid ].update (locs )
486+ else :
487+ var_refs_merged [sid ] = set (locs )
488+
489+ var_assigns_merged : Dict [str , Set [Range ]] = {}
490+ for var , ranges in self ._local_variable_assignments .items ():
491+ sid = var .stable_id
492+ if sid in var_assigns_merged :
493+ var_assigns_merged [sid ].update (ranges )
494+ else :
495+ var_assigns_merged [sid ] = set (ranges )
496+
453497 return NamespaceData (
454498 source = self .source ,
455499 source_id = str (self .source_id ) if self .source_id else None ,
@@ -459,16 +503,15 @@ def to_data(self) -> NamespaceData:
459503 imports = list (self ._import_entries .keys ()),
460504 diagnostics = list (self ._diagnostics ),
461505 test_case_definitions = list (self ._test_case_definitions ),
462- keyword_references = {kw .stable_id : set (locs ) for kw , locs in self ._keyword_references .items ()},
463- variable_references = {var .stable_id : set (locs ) for var , locs in self ._variable_references .items ()},
464- local_variable_assignments = {
465- var .stable_id : set (ranges ) for var , ranges in self ._local_variable_assignments .items ()
466- },
506+ keyword_references = kw_refs_merged ,
507+ variable_references = var_refs_merged ,
508+ local_variable_assignments = var_assigns_merged ,
467509 namespace_references = ns_refs ,
468510 keyword_tag_references = {k : set (v ) for k , v in self ._keyword_tag_references .items ()},
469511 testcase_tag_references = {k : set (v ) for k , v in self ._testcase_tag_references .items ()},
470512 metadata_references = {k : set (v ) for k , v in self ._metadata_references .items ()},
471513 local_scopes = list (self ._scope_tree .local_scopes ),
514+ variable_definitions = all_var_defs ,
472515 )
473516
474517 @classmethod
@@ -528,11 +571,29 @@ def from_data(
528571 for var in scope .iter_all ():
529572 var_by_id [var .stable_id ] = var
530573
574+ # Add keyword argument_definitions from all resolved keywords
575+ # to var_by_id. This covers ArgumentDefinition and
576+ # LibraryArgumentDefinition objects that are created during
577+ # Phase 3 analysis but aren't part of the file's own scope.
578+ for kw in kw_by_id .values ():
579+ if kw .argument_definitions :
580+ for arg_var in kw .argument_definitions :
581+ var_by_id [arg_var .stable_id ] = arg_var
582+
531583 # Variables from local scopes (block-level LOCAL_VARIABLE, arguments, etc.)
532584 for ls in data .local_scopes :
533585 for sv in ls .variables :
534586 var_by_id [sv .variable .stable_id ] = sv .variable
535587
588+ # Fallback: use stored variable definitions for any stable_ids
589+ # not found in the rebuilt scope. This handles variables whose
590+ # stable_ids differ due to re-parsing differences (e.g. col_offset
591+ # for variables with '=' suffix) and keyword argument definitions
592+ # from imported keywords that aren't in the file's own scope.
593+ for sid , var_def in data .variable_definitions .items ():
594+ if sid not in var_by_id :
595+ var_by_id [sid ] = var_def
596+
536597 # --- Reconstruct reference dicts ---
537598 keyword_references : Dict [KeywordDoc , Set [Location ]] = {}
538599 for sid , locs in data .keyword_references .items ():
0 commit comments