@@ -201,8 +201,9 @@ class ObjCMethod extends AstNode {
201201  final  ObjCBuiltInFunctions  builtInFunctions;
202202  final  String ?  dartDoc;
203203  final  String  originalName;
204-   final   String  name;
204+   String  name;
205205  String ?  dartMethodName;
206+   late  final  String  protocolMethodName;
206207  final  ObjCProperty ?  property;
207208  Type  returnType;
208209  final  List <Parameter > params;
@@ -244,6 +245,43 @@ class ObjCMethod extends AstNode {
244245  })  :  params =  params_ ??  [],
245246        selObject =  builtInFunctions.getSelObject (originalName);
246247
248+   // Must be called after all params are added to the method. 
249+   void  finalizeParams () {
250+     protocolMethodName =  name.replaceAll (':' , '_' );
251+ 
252+     // Split the name at the ':'. The first chunk is the name of the method, and 
253+     // the rest of the chunks are named parameters. Eg NSString's 
254+     //   - compare:options:range: 
255+     // method becomes 
256+     //   NSComparisonResult compare(NSString string, 
257+     //       {required NSStringCompareOptions options, required NSRange range}) 
258+     final  chunks =  name.split (':' );
259+ 
260+     // Details: 
261+     //  - The first chunk is always the new Dart method name. 
262+     //  - The rest of the chunks correspond to the params, so there's always 
263+     //    one more chunk than the number of params. 
264+     //  - The correspondence between the chunks and the params is non-trivial: 
265+     //    - The ObjC name always ends with a ':' unless there are no ':' at all. 
266+     //    - The first param is an ordinary param, not a named param. 
267+     final  correctNumParams =  chunks.length ==  params.length +  1 ;
268+     final  lastChunkIsEmpty =  chunks.length ==  1  ||  chunks.last.isEmpty;
269+     if  (correctNumParams &&  lastChunkIsEmpty) {
270+       // Take the first chunk as the name, ignore the last chunk, and map the 
271+       // rest to each of the params after the first. 
272+       name =  chunks[0 ];
273+       for  (var  i =  1 ; i <  params.length; ++ i) {
274+         params[i].name =  chunks[i];
275+       }
276+     } else  {
277+       // There are a few methods that don't obey these rules, eg due to variadic 
278+       // parameters. Most of these are omitted from the bindings as they're not 
279+       // supported yet. But as a fallback, just replace all the ':' in the name 
280+       // with '_', like we do for protocol methods. 
281+       name =  protocolMethodName;
282+     }
283+   }
284+ 
247285  bool  get  isProperty => 
248286      kind ==  ObjCMethodKind .propertyGetter || 
249287      kind ==  ObjCMethodKind .propertySetter;
@@ -271,9 +309,11 @@ class ObjCMethod extends AstNode {
271309    )..fillProtocolTrampoline ();
272310  }
273311
274-   String  getDartMethodName (UniqueNamer  uniqueNamer,
275-       {bool  usePropertyNaming =  true }) {
276-     if  (property !=  null  &&  usePropertyNaming) {
312+   String  getDartProtocolMethodName (UniqueNamer  uniqueNamer) => 
313+       uniqueNamer.makeUnique (protocolMethodName);
314+ 
315+   String  getDartMethodName (UniqueNamer  uniqueNamer) {
316+     if  (property !=  null ) {
277317      // A getter and a setter are allowed to have the same name, so we can't 
278318      // just run the name through uniqueNamer. Instead they need to share 
279319      // the dartName, which is run through uniqueNamer. 
@@ -282,12 +322,8 @@ class ObjCMethod extends AstNode {
282322      }
283323      return  property! .dartName! ;
284324    }
285-     // Objective C methods can look like: 
286-     // foo 
287-     // foo: 
288-     // foo:someArgName: 
289-     // So replace all ':' with '_'. 
290-     return  uniqueNamer.makeUnique (name.replaceAll (':' , '_' ));
325+ 
326+     return  uniqueNamer.makeUnique (name);
291327  }
292328
293329  bool  sameAs (ObjCMethod  other) {
@@ -345,20 +381,35 @@ class ObjCMethod extends AstNode {
345381    return  returnType.getDartType (w);
346382  }
347383
384+   static  String  _paramToStr (Writer  w, Parameter  p) => 
385+       '${p .isCovariant  ? 'covariant '  : '' }${p .type .getDartType (w )} ${p .name }' ;
386+ 
387+   static  String  _paramToNamed (Writer  w, Parameter  p) => 
388+       '${p .isNullable  ? ''  : 'required ' }${_paramToStr (w , p )}' ;
389+ 
390+   static  String  _joinParamStr (Writer  w, List <Parameter > params) {
391+     if  (params.isEmpty) return  '' ;
392+     if  (params.length ==  1 ) return  _paramToStr (w, params.first);
393+     final  named =  params.sublist (1 ).map ((p) =>  _paramToNamed (w, p)).join (',' );
394+     return  '${_paramToStr (w , params .first )}, {$named }' ;
395+   }
396+ 
348397  String  generateBindings (
349398      Writer  w, ObjCInterface  target, UniqueNamer  methodNamer) {
350-     dartMethodName ?? =  getDartMethodName (methodNamer);
399+     if  (dartMethodName ==  null ) {
400+       dartMethodName =  getDartMethodName (methodNamer);
401+       final  paramNamer =  UniqueNamer (parent:  methodNamer);
402+       for  (final  p in  params) {
403+         p.name =  paramNamer.makeUnique (p.name);
404+       }
405+     }
351406    final  methodName =  dartMethodName! ;
352407    final  upperName =  methodName[0 ].toUpperCase () +  methodName.substring (1 );
353408    final  s =  StringBuffer ();
354409
355410    final  targetType =  target.getDartType (w);
356411    final  returnTypeStr =  _getConvertedReturnType (w, targetType);
357-     final  paramStr =  < String > [
358-       for  (final  p in  params)
359-         '${p .isCovariant  ? 'covariant '  : '' }' 
360-             '${p .type .getDartType (w )} ${p .name }' ,
361-     ].join (', ' );
412+     final  paramStr =  _joinParamStr (w, params);
362413
363414    // The method declaration. 
364415    s.write ('\n   ${makeDartDoc (dartDoc )}  ' );
0 commit comments