@@ -107,6 +107,26 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
107
107
108
108
IdentifierNameSyntax origName = IdentifierName ( externParam . Identifier . ValueText ) ;
109
109
110
+ bool isArray = false ;
111
+ bool isNullTerminated = false ; // TODO
112
+ short ? countParamIndex = null ;
113
+ int ? countConst = null ;
114
+ if ( this . FindInteropDecorativeAttribute ( paramAttributes , NativeArrayInfoAttribute ) is CustomAttribute nativeArrayInfoAttribute )
115
+ {
116
+ isArray = true ;
117
+ NativeArrayInfo nativeArrayInfo = DecodeNativeArrayInfoAttribute ( nativeArrayInfoAttribute ) ;
118
+ countParamIndex = nativeArrayInfo . CountParamIndex ;
119
+ countConst = nativeArrayInfo . CountConst ;
120
+ }
121
+ else if ( externParam . Type is PointerTypeSyntax { ElementType : PredefinedTypeSyntax { Keyword . RawKind : ( int ) SyntaxKind . ByteKeyword } } && this . FindInteropDecorativeAttribute ( paramAttributes , MemorySizeAttribute ) is CustomAttribute memorySizeAttribute )
122
+ {
123
+ // A very special case as documented in https://github.com/microsoft/win32metadata/issues/1555
124
+ // where MemorySizeAttribute is applied to byte* parameters to indicate the size of the buffer.
125
+ isArray = true ;
126
+ MemorySize memorySize = DecodeMemorySizeAttribute ( memorySizeAttribute ) ;
127
+ countParamIndex = memorySize . BytesParamIndex ;
128
+ }
129
+
110
130
if ( mustRemainAsPointer )
111
131
{
112
132
// This block intentionally left blank, so as to disable further processing that might try to
@@ -243,80 +263,19 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
243
263
}
244
264
}
245
265
246
- bool isArray = false ;
247
- bool isNullTerminated = false ; // TODO
248
- short ? sizeParamIndex = null ;
249
- int ? sizeConst = null ;
250
- if ( this . FindInteropDecorativeAttribute ( paramAttributes , NativeArrayInfoAttribute ) is CustomAttribute att )
251
- {
252
- isArray = true ;
253
- NativeArrayInfo nativeArrayInfo = DecodeNativeArrayInfoAttribute ( att ) ;
254
- sizeParamIndex = nativeArrayInfo . CountParamIndex ;
255
- sizeConst = nativeArrayInfo . CountConst ;
256
- }
257
- else if ( externParam . Type is PointerTypeSyntax { ElementType : PredefinedTypeSyntax { Keyword . RawKind : ( int ) SyntaxKind . ByteKeyword } } && this . FindInteropDecorativeAttribute ( paramAttributes , MemorySizeAttribute ) is CustomAttribute att2 )
258
- {
259
- // A very special case as documented in https://github.com/microsoft/win32metadata/issues/1555
260
- // where MemorySizeAttribute is applied to byte* parameters to indicate the size of the buffer.
261
- isArray = true ;
262
- MemorySize memorySize = DecodeMemorySizeAttribute ( att2 ) ;
263
- sizeParamIndex = memorySize . BytesParamIndex ;
264
- }
265
-
266
266
IdentifierNameSyntax localName = IdentifierName ( origName + "Local" ) ;
267
267
if ( isArray )
268
268
{
269
269
// TODO: add support for in/out size parameters. (e.g. RSGetViewports)
270
270
// TODO: add support for lists of pointers via a generated pointer-wrapping struct (e.g. PSSetSamplers)
271
271
272
- // It is possible that sizeParamIndex points to a parameter that is not on the extern method
272
+ // It is possible that countParamIndex points to a parameter that is not on the extern method
273
273
// when the parameter is the last one and was moved to a return value.
274
- if ( sizeParamIndex . HasValue
275
- && this . canUseSpan
276
- && externMethodDeclaration . ParameterList . Parameters . Count > sizeParamIndex . Value
277
- && ! ( externMethodDeclaration . ParameterList . Parameters [ sizeParamIndex . Value ] . Type is PointerTypeSyntax )
278
- && ! ( externMethodDeclaration . ParameterList . Parameters [ sizeParamIndex . Value ] . Modifiers . Any ( SyntaxKind . OutKeyword ) || externMethodDeclaration . ParameterList . Parameters [ sizeParamIndex . Value ] . Modifiers . Any ( SyntaxKind . RefKeyword ) )
279
- && ! isPointerToPointer )
274
+ if ( ! isPointerToPointer && TryHandleCountParam ( elementType , nullableSource : true ) )
280
275
{
281
- signatureChanged = true ;
282
- bool remainsRefType = true ;
283
- if ( externParam . Type is PointerTypeSyntax )
284
- {
285
- remainsRefType = false ;
286
- parameters [ param . SequenceNumber - 1 ] = parameters [ param . SequenceNumber - 1 ]
287
- . WithType ( ( isIn ? MakeReadOnlySpanOfT ( elementType ) : MakeSpanOfT ( elementType ) ) . WithTrailingTrivia ( TriviaList ( Space ) ) ) ;
288
- fixedBlocks . Add ( VariableDeclaration ( externParam . Type ) . AddVariables (
289
- VariableDeclarator ( localName . Identifier ) . WithInitializer ( EqualsValueClause ( origName ) ) ) ) ;
290
- arguments [ param . SequenceNumber - 1 ] = Argument ( localName ) ;
291
- }
292
-
293
- if ( lengthParamUsedBy . TryGetValue ( sizeParamIndex . Value , out int userIndex ) )
294
- {
295
- // Multiple array parameters share a common 'length' parameter.
296
- // Since we're making this a little less obvious, add a quick if check in the helper method
297
- // that enforces that all such parameters have a common span length.
298
- ExpressionSyntax otherUserName = IdentifierName ( parameters [ userIndex ] . Identifier . ValueText ) ;
299
- leadingStatements . Add ( IfStatement (
300
- BinaryExpression (
301
- SyntaxKind . NotEqualsExpression ,
302
- GetSpanLength ( otherUserName , parameters [ userIndex ] . Type is ArrayTypeSyntax ) ,
303
- GetSpanLength ( origName , remainsRefType ) ) ,
304
- ThrowStatement ( ObjectCreationExpression ( IdentifierName ( nameof ( ArgumentException ) ) ) . WithArgumentList ( ArgumentList ( ) ) ) ) ) ;
305
- }
306
- else
307
- {
308
- lengthParamUsedBy . Add ( sizeParamIndex . Value , param . SequenceNumber - 1 ) ;
309
- }
310
-
311
- ExpressionSyntax sizeArgExpression = GetSpanLength ( origName , remainsRefType ) ;
312
- if ( ! ( parameters [ sizeParamIndex . Value ] . Type is PredefinedTypeSyntax { Keyword : { RawKind : ( int ) SyntaxKind . IntKeyword } } ) )
313
- {
314
- sizeArgExpression = CastExpression ( parameters [ sizeParamIndex . Value ] . Type ! , sizeArgExpression ) ;
315
- }
316
-
317
- arguments [ sizeParamIndex . Value ] = Argument ( sizeArgExpression ) ;
276
+ // This block intentionally left blank.
318
277
}
319
- else if ( sizeConst . HasValue && ! isPointerToPointer && this . canUseSpan && externParam . Type is PointerTypeSyntax )
278
+ else if ( countConst . HasValue && ! isPointerToPointer && this . canUseSpan && externParam . Type is PointerTypeSyntax )
320
279
{
321
280
// TODO: add support for lists of pointers via a generated pointer-wrapping struct
322
281
signatureChanged = true ;
@@ -333,7 +292,7 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
333
292
BinaryExpression (
334
293
SyntaxKind . LessThanExpression ,
335
294
GetSpanLength ( origName , false /* we've converted it to be a span */ ) ,
336
- LiteralExpression ( SyntaxKind . NumericLiteralExpression , Literal ( sizeConst . Value ) ) ) ,
295
+ LiteralExpression ( SyntaxKind . NumericLiteralExpression , Literal ( countConst . Value ) ) ) ,
337
296
ThrowStatement ( ObjectCreationExpression ( IdentifierName ( nameof ( ArgumentException ) ) ) . WithArgumentList ( ArgumentList ( ) ) ) ) ) ;
338
297
}
339
298
else if ( isNullTerminated && isConst && parameters [ param . SequenceNumber - 1 ] . Type is PointerTypeSyntax { ElementType : PredefinedTypeSyntax { Keyword : { RawKind : ( int ) SyntaxKind . CharKeyword } } } )
@@ -475,6 +434,24 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
475
434
Argument ( LiteralExpression ( SyntaxKind . NumericLiteralExpression , Literal ( 0 ) ) ) ,
476
435
Argument ( MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression , localWstrName , IdentifierName ( "Length" ) ) ) ) ) ) ) ) ;
477
436
}
437
+ else if ( ! isIn && isOut && this . canUseSpan && externParam . Type is QualifiedNameSyntax { Right : { Identifier : { ValueText : "PWSTR" } } } )
438
+ {
439
+ IdentifierNameSyntax localName = IdentifierName ( origName + "Local" ) ;
440
+ signatureChanged = true ;
441
+ parameters [ param . SequenceNumber - 1 ] = externParam
442
+ . WithType ( MakeSpanOfT ( PredefinedType ( Token ( SyntaxKind . CharKeyword ) ) ) ) ;
443
+
444
+ // fixed (char* pParam1 = Param1)
445
+ fixedBlocks . Add ( VariableDeclaration ( PointerType ( PredefinedType ( Token ( SyntaxKind . CharKeyword ) ) ) ) . AddVariables (
446
+ VariableDeclarator ( localName . Identifier ) . WithInitializer ( EqualsValueClause (
447
+ origName ) ) ) ) ;
448
+
449
+ // Use the char* pointer as the argument instead of the parameter.
450
+ arguments [ param . SequenceNumber - 1 ] = Argument ( localName ) ;
451
+
452
+ // Remove the size parameter if one exists.
453
+ TryHandleCountParam ( PredefinedType ( Token ( SyntaxKind . CharKeyword ) ) , nullableSource : false ) ;
454
+ }
478
455
else if ( isIn && isOptional && ! isOut && isManagedParameterType && parameterTypeInfo is PointerTypeHandleInfo ptrInfo && ptrInfo . ElementType . IsValueType ( parameterTypeSyntaxSettings ) is true && this . canUseUnsafeAsRef )
479
456
{
480
457
// The extern method couldn't have exposed the parameter as a pointer because the type is managed.
@@ -504,6 +481,58 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
504
481
localName ,
505
482
nullRef ) ) ;
506
483
}
484
+
485
+ bool TryHandleCountParam ( TypeSyntax elementType , bool nullableSource )
486
+ {
487
+ IdentifierNameSyntax localName = IdentifierName ( origName + "Local" ) ;
488
+ if ( countParamIndex . HasValue
489
+ && this . canUseSpan
490
+ && externMethodDeclaration . ParameterList . Parameters . Count > countParamIndex . Value
491
+ && ! ( externMethodDeclaration . ParameterList . Parameters [ countParamIndex . Value ] . Type is PointerTypeSyntax )
492
+ && ! ( externMethodDeclaration . ParameterList . Parameters [ countParamIndex . Value ] . Modifiers . Any ( SyntaxKind . OutKeyword ) || externMethodDeclaration . ParameterList . Parameters [ countParamIndex . Value ] . Modifiers . Any ( SyntaxKind . RefKeyword ) ) )
493
+ {
494
+ signatureChanged = true ;
495
+ bool remainsRefType = nullableSource ;
496
+ if ( externParam . Type is PointerTypeSyntax )
497
+ {
498
+ remainsRefType = false ;
499
+ parameters [ param . SequenceNumber - 1 ] = parameters [ param . SequenceNumber - 1 ]
500
+ . WithType ( ( isIn ? MakeReadOnlySpanOfT ( elementType ) : MakeSpanOfT ( elementType ) ) . WithTrailingTrivia ( TriviaList ( Space ) ) ) ;
501
+ fixedBlocks . Add ( VariableDeclaration ( externParam . Type ) . AddVariables (
502
+ VariableDeclarator ( localName . Identifier ) . WithInitializer ( EqualsValueClause ( origName ) ) ) ) ;
503
+ arguments [ param . SequenceNumber - 1 ] = Argument ( localName ) ;
504
+ }
505
+
506
+ if ( lengthParamUsedBy . TryGetValue ( countParamIndex . Value , out int userIndex ) )
507
+ {
508
+ // Multiple array parameters share a common 'length' parameter.
509
+ // Since we're making this a little less obvious, add a quick if check in the helper method
510
+ // that enforces that all such parameters have a common span length.
511
+ ExpressionSyntax otherUserName = IdentifierName ( parameters [ userIndex ] . Identifier . ValueText ) ;
512
+ leadingStatements . Add ( IfStatement (
513
+ BinaryExpression (
514
+ SyntaxKind . NotEqualsExpression ,
515
+ GetSpanLength ( otherUserName , parameters [ userIndex ] . Type is ArrayTypeSyntax ) ,
516
+ GetSpanLength ( origName , remainsRefType ) ) ,
517
+ ThrowStatement ( ObjectCreationExpression ( IdentifierName ( nameof ( ArgumentException ) ) ) . WithArgumentList ( ArgumentList ( ) ) ) ) ) ;
518
+ }
519
+ else
520
+ {
521
+ lengthParamUsedBy . Add ( countParamIndex . Value , param . SequenceNumber - 1 ) ;
522
+ }
523
+
524
+ ExpressionSyntax sizeArgExpression = GetSpanLength ( origName , remainsRefType ) ;
525
+ if ( ! ( parameters [ countParamIndex . Value ] . Type is PredefinedTypeSyntax { Keyword : { RawKind : ( int ) SyntaxKind . IntKeyword } } ) )
526
+ {
527
+ sizeArgExpression = CastExpression ( parameters [ countParamIndex . Value ] . Type ! , sizeArgExpression ) ;
528
+ }
529
+
530
+ arguments [ countParamIndex . Value ] = Argument ( sizeArgExpression ) ;
531
+ return true ;
532
+ }
533
+
534
+ return false ;
535
+ }
507
536
}
508
537
509
538
TypeSyntax ? returnSafeHandleType = originalSignature . ReturnType is HandleTypeHandleInfo returnTypeHandleInfo
0 commit comments