@@ -222,6 +222,80 @@ def detect_universal_ctags() -> bool:
222222 except Exception :
223223 return False
224224
225+ def normalize_function_signature (signature : str ) -> str :
226+ """
227+ Normalize a function signature by removing parameter names, keeping only types.
228+
229+ This handles cases where header declarations and implementations have different parameter names.
230+ Uses a simple heuristic: the last word in each parameter is typically the parameter name.
231+
232+ For example:
233+ - "ltoa(long val, char *s, int radix)" -> "ltoa(long,char *,int)"
234+ - "ltoa(long value, char *result, int base)" -> "ltoa(long,char *,int)"
235+
236+ Args:
237+ signature: The function signature string, e.g., "(long val, char *s, int radix)"
238+
239+ Returns:
240+ Normalized signature with parameter names removed, e.g., "(long,char *,int)"
241+ """
242+ if not signature :
243+ return signature
244+
245+ # Normalize signatures: treat (void) and () as equivalent (both mean no parameters)
246+ if signature == "(void)" :
247+ return "()"
248+
249+ if not (signature .startswith ("(" ) and signature .endswith (")" )):
250+ return signature
251+
252+ # Handle const qualifier at the end (e.g., "(int i) const")
253+ const_qualifier = ""
254+ if signature .endswith (" const" ):
255+ signature = signature [:- 6 ] # Remove " const"
256+ const_qualifier = " const"
257+
258+ # Extract parameter list without parentheses
259+ param_list = signature [1 :- 1 ]
260+ if not param_list .strip ():
261+ return "()" + const_qualifier
262+
263+ # Split by comma and process each parameter
264+ params = []
265+ for param in param_list .split ("," ):
266+ param = param .strip ()
267+ if not param :
268+ continue
269+
270+ # Handle default parameters (e.g., "int x = 5")
271+ if "=" in param :
272+ param = param .split ("=" )[0 ].strip ()
273+
274+ # Simple heuristic: remove the last word (parameter name)
275+ # This works for most cases: "int x" -> "int", "char *ptr" -> "char *"
276+ tokens = param .split ()
277+ if len (tokens ) > 1 :
278+ # Check if the last token starts with * (like *ptr) - this is a pointer parameter name
279+ if tokens [- 1 ].startswith ('*' ):
280+ # Remove the last token and add * to the type
281+ type_tokens = tokens [:- 1 ] + ['*' ]
282+ params .append (" " .join (type_tokens ))
283+ else :
284+ # Remove the last token (parameter name)
285+ type_tokens = tokens [:- 1 ]
286+ params .append (" " .join (type_tokens ))
287+ else :
288+ # Single word - could be a type or parameter name
289+ # In C/C++, single-word parameters are rare, so we assume it's a type
290+ # This handles both basic types (int, char) and typedefs (MACType, boolean)
291+ params .append (tokens [0 ])
292+
293+ result = "(" + "," .join (params ) + ")"
294+ if const_qualifier :
295+ result += const_qualifier
296+
297+ return result
298+
225299def build_qname_from_tag (tag : dict ) -> str :
226300 """
227301 Compose a qualified name for a function/method using scope + name + signature.
@@ -231,9 +305,8 @@ def build_qname_from_tag(tag: dict) -> str:
231305 name = tag .get ("name" ) or ""
232306 signature = tag .get ("signature" ) or ""
233307
234- # Normalize signatures: treat (void) and () as equivalent (both mean no parameters)
235- if signature == "(void)" :
236- signature = "()"
308+ # Normalize the signature to remove parameter names
309+ signature = normalize_function_signature (signature )
237310
238311 qparts = []
239312 if scope :
0 commit comments