@@ -95,6 +95,7 @@ def __init__(self, context: DWARFContext, base_dir: str):
9595 self ._cache = {}
9696 self ._param_names : dict [str , list [str ]] = {}
9797 self ._functions : dict [str , list [Function ]] = defaultdict (list )
98+ self ._templates : dict [str | int , dict [int , list [Template ]]] = defaultdict (lambda : defaultdict (list ))
9899
99100 @property
100101 def files (self ) -> Generator [tuple [str , dict [int , list [Object ]]]]:
@@ -106,11 +107,11 @@ def files(self) -> Generator[tuple[str, dict[int, list[Object]]]]:
106107 List of files
107108 """
108109 for i , cu in (
109- pbar := tqdm (
110- enumerate (self .context .compile_units ),
111- total = self .context .num_compile_units ,
112- bar_format = "[{n_fmt}/{total_fmt}] {desc}" ,
113- )
110+ pbar := tqdm (
111+ enumerate (self .context .compile_units ),
112+ total = self .context .num_compile_units ,
113+ bar_format = "[{n_fmt}/{total_fmt}] {desc}" ,
114+ )
114115 ):
115116 cu_die = cu .unit_die
116117 name = cu_die .short_name
@@ -191,7 +192,9 @@ def visit_compile_unit(self, die: DWARFDie):
191192 self .visit (child )
192193 if child .offset in self ._cache :
193194 if template := self ._cache [child .offset ].template :
194- self ._add (decl_file , decl_line , template )
195+ if template := self ._register_template (decl_file , decl_line , template ):
196+ self ._add (decl_file , decl_line , template )
197+
195198 self ._add (decl_file , decl_line , self ._cache [child .offset ])
196199
197200 elif child .tag in {
@@ -265,7 +268,7 @@ def visit_namespace(self, die: DWARFDie) -> None:
265268 member .parent = namespace
266269 if template := member .template :
267270 template .parent = namespace
268- if template not in self ._files [ decl_file ][ decl_line ] :
271+ if template := self ._register_template ( decl_file , decl_line , template ) :
269272 self ._add (decl_file , decl_line , template )
270273
271274 self ._add (decl_file , decl_line , member )
@@ -604,11 +607,33 @@ def visit_imported_declaration(self, die: DWARFDie) -> None:
604607 self ._cache [die .offset ] = imported_decl
605608
606609 def visit_template_type_parameter (self , die : DWARFDie ) -> None :
607- self ._cache [die .offset ] = TemplateParameter (die .short_name , TemplateParameterKind .TYPE )
610+ param = TemplateParameter (die .short_name , TemplateParameterKind .TYPE )
611+
612+ # A template type parameter entry has a DW_AT_type attribute
613+ # describing the actual type by which the formal is replaced.
614+ if ty := die .find ("DW_AT_type" ):
615+ param .arg = get_qualified_type (ty .as_referenced_die ())
616+ else :
617+ param .arg = "void"
618+
619+ for attribute in die .attributes :
620+ if attribute .name in {"DW_AT_name" , "DW_AT_type" }:
621+ continue
622+
623+ match attribute .name :
624+ case "DW_AT_default_value" :
625+ param .default = param .arg
626+ case _:
627+ raise ValueError (f"Unhandled attribute { attribute .name } " )
628+
629+ for child in die .children :
630+ raise ValueError (f"Unhandled child tag { child .tag } " )
631+
632+ self ._cache [die .offset ] = param
608633
609634 def visit_template_value_parameter (self , die : DWARFDie ) -> None :
610635 ty = get_qualified_type (die .find ("DW_AT_type" ).as_referenced_die ())
611- self ._cache [die .offset ] = TemplateParameter (die .short_name , TemplateParameterKind .CONSTANT , value_type = ty )
636+ self ._cache [die .offset ] = TemplateParameter (die .short_name , TemplateParameterKind .CONSTANT , type = ty )
612637
613638 def visit_GNU_template_parameter_pack (self , die : DWARFDie ) -> None :
614639 self ._cache [die .offset ] = TemplateParameter (die .short_name , TemplateParameterKind .PACK )
@@ -630,6 +655,22 @@ def _add(self, filepath: str, lineno: int, obj: Object) -> None:
630655
631656 lines .append (obj )
632657
658+ def _register_template (self , key : str | int , lineno : int , template : Template ) -> Template | None :
659+ templates = self ._templates [key ][lineno ]
660+
661+ # make a copy for template declaration
662+ template = copy .copy (template )
663+ for parameter in template .parameters :
664+ parameter .arg = None # declaration must not have type replacement
665+
666+ # try to merge with existing templates
667+ for t in templates :
668+ if t .merge (template ):
669+ return None
670+
671+ templates .append (template )
672+ return template
673+
633674 def _handle_attribute (self , die : DWARFDie ) -> None :
634675 if not die .decl_file or not die .decl_line or not die .short_name :
635676 return
@@ -788,7 +829,7 @@ def _handle_struct(self, die: DWARFDie, struct: Struct) -> None:
788829 if template .access is None :
789830 template .access = access
790831
791- if template not in lines :
832+ if template := self . _register_template ( die . offset , child . decl_line , template ) :
792833 lines .append (template )
793834
794835 lines .append (member )
0 commit comments