@@ -222,6 +222,80 @@ def detect_universal_ctags() -> bool:
222
222
except Exception :
223
223
return False
224
224
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
+
225
299
def build_qname_from_tag (tag : dict ) -> str :
226
300
"""
227
301
Compose a qualified name for a function/method using scope + name + signature.
@@ -231,9 +305,8 @@ def build_qname_from_tag(tag: dict) -> str:
231
305
name = tag .get ("name" ) or ""
232
306
signature = tag .get ("signature" ) or ""
233
307
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 )
237
310
238
311
qparts = []
239
312
if scope :
0 commit comments