@@ -153,7 +153,7 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
153153
154154 if ( isRefParam )
155155 {
156- Context . Return . Write ( "_{0}" , param . Name ) ;
156+ Context . Return . Write ( Generator . GeneratedIdentifier ( param . Name ) ) ;
157157 return true ;
158158 }
159159
@@ -172,9 +172,11 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
172172 }
173173 else
174174 {
175- var templateParameter = type as TemplateParameterType ;
176- if ( templateParameter != null )
177- Context . Return . Write ( $ "({ templateParameter . Parameter . Name } ) (object) *") ;
175+ var substitution = pointer . Pointee . Desugar (
176+ resolveTemplateSubstitution : false ) as TemplateParameterSubstitutionType ;
177+ if ( substitution != null )
178+ Context . Return . Write ( $@ "({
179+ substitution . ReplacedParameter . Parameter . Name } ) (object) *" ) ;
178180 }
179181 }
180182
@@ -492,49 +494,6 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
492494 if ( ! VisitType ( pointer , quals ) )
493495 return false ;
494496
495- var qualifiedPointer = new QualifiedType ( pointer , quals ) ;
496-
497- var templateSubstitution = pointer . Pointee as TemplateParameterSubstitutionType ;
498- PointerType realPointer = null ;
499- if ( templateSubstitution != null )
500- realPointer = templateSubstitution . Replacement . Type . Desugar ( ) as PointerType ;
501- realPointer = realPointer ?? pointer ;
502- if ( Context . Function != null &&
503- ( realPointer . IsPrimitiveTypeConvertibleToRef ( ) ||
504- ( templateSubstitution != null && realPointer . Pointee . IsEnumType ( ) ) ) &&
505- Context . MarshalKind != MarshalKind . VTableReturnValue )
506- {
507- var refParamPtr = $ "__refParamPtr{ Context . ParameterIndex } ";
508- if ( templateSubstitution != null )
509- {
510- var castParam = $ "__{ Context . Parameter . Name } { Context . ParameterIndex } ";
511- Context . Before . Write ( $ "var { castParam } = ({ templateSubstitution } ) ") ;
512- if ( realPointer != pointer )
513- Context . Before . Write ( $ "({ CSharpTypePrinter . IntPtrType } ) ") ;
514- Context . Before . WriteLine ( $ "(object) { Context . Parameter . Name } ;") ;
515- Context . Before . WriteLine ( $ "var { refParamPtr } = &{ castParam } ;") ;
516- Context . Return . Write ( refParamPtr ) ;
517- return true ;
518- }
519- if ( Context . Function . OperatorKind != CXXOperatorKind . Subscript )
520- {
521- if ( Context . Parameter . Kind == ParameterKind . PropertyValue ||
522- qualifiedPointer . IsConstRefToPrimitive ( ) )
523- {
524- Context . Return . Write ( $ "&{ Context . Parameter . Name } ") ;
525- }
526- else
527- {
528- Context . Before . WriteLine (
529- $ "fixed ({ realPointer } { refParamPtr } = &{ Context . Parameter . Name } )") ;
530- Context . HasCodeBlock = true ;
531- Context . Before . WriteOpenBraceAndIndent ( ) ;
532- Context . Return . Write ( refParamPtr ) ;
533- }
534- return true ;
535- }
536- }
537-
538497 var param = Context . Parameter ;
539498 var isRefParam = param != null && ( param . IsInOut || param . IsOut ) ;
540499
@@ -543,23 +502,69 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
543502 {
544503 if ( param . IsOut )
545504 {
505+ MarshalString ( pointee ) ;
546506 Context . Return . Write ( "IntPtr.Zero" ) ;
547507 Context . ArgumentPrefix . Write ( "&" ) ;
548508 return true ;
549509 }
550- pointer . QualifiedPointee . Visit ( this ) ;
551510 if ( param . IsInOut )
511+ {
512+ MarshalString ( pointee ) ;
513+ pointer . QualifiedPointee . Visit ( this ) ;
552514 Context . ArgumentPrefix . Write ( "&" ) ;
515+ }
553516 else
554- Context . Cleanup . WriteLine ( "Marshal.FreeHGlobal({0});" , Context . ArgName ) ;
517+ {
518+ pointer . QualifiedPointee . Visit ( this ) ;
519+ Context . Cleanup . WriteLine ( $ "Marshal.FreeHGlobal({ Context . ArgName } );") ;
520+ }
555521 return true ;
556522 }
557523
558- if ( pointee is FunctionType )
559- return VisitDelegateType ( ) ;
524+ var finalPointee = ( pointee . GetFinalPointee ( ) ?? pointee ) . Desugar ( ) ;
525+ if ( finalPointee . IsPrimitiveType ( out PrimitiveType primitive ) ||
526+ finalPointee . IsEnumType ( ) )
527+ {
528+ if ( isRefParam )
529+ {
530+ var local = Generator . GeneratedIdentifier ( $@ "{
531+ param . Name } { Context . ParameterIndex } " ) ;
532+ Context . Before . WriteLine ( $@ "fixed ({
533+ pointer . Visit ( typePrinter ) } { local } = &{ param . Name } )" ) ;
534+ Context . HasCodeBlock = true ;
535+ Context . Before . WriteOpenBraceAndIndent ( ) ;
536+ Context . Return . Write ( local ) ;
537+ return true ;
538+ }
560539
561- Class @class ;
562- if ( pointee . TryGetClass ( out @class ) && @class . IsValueType )
540+ if ( Context . Context . Options . MarshalCharAsManagedChar &&
541+ primitive == PrimitiveType . Char )
542+ {
543+ Context . Return . Write ( $ "({ typePrinter . PrintNative ( pointer ) } ) ") ;
544+ Context . Return . Write ( param . Name ) ;
545+ return true ;
546+ }
547+
548+ pointer . QualifiedPointee . Visit ( this ) ;
549+ bool isVoid = primitive == PrimitiveType . Void && pointee . IsAddress ( ) ;
550+ if ( pointer . Pointee . Desugar ( false ) is TemplateParameterSubstitutionType ||
551+ isVoid )
552+ {
553+ var local = Generator . GeneratedIdentifier ( $@ "{
554+ param . Name } { Context . ParameterIndex } " ) ;
555+ string cast = isVoid ? $@ "({ pointee . Visit (
556+ new CppTypePrinter { PrintTypeQualifiers = false } ) } ) " : string . Empty ;
557+ Context . Before . WriteLine ( $ "var { local } = { cast } { Context . Return } ;") ;
558+ Context . Return . StringBuilder . Clear ( ) ;
559+ Context . Return . Write ( local ) ;
560+ }
561+ if ( new QualifiedType ( pointer , quals ) . IsConstRefToPrimitive ( ) )
562+ Context . Return . StringBuilder . Insert ( 0 , '&' ) ;
563+
564+ return true ;
565+ }
566+
567+ if ( pointee . TryGetClass ( out Class @class ) && @class . IsValueType )
563568 {
564569 if ( Context . Parameter . Usage == ParameterUsage . Out )
565570 {
@@ -581,63 +586,13 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
581586 return true ;
582587 }
583588
584- var finalPointee = pointer . GetFinalPointee ( ) ;
585- PrimitiveType primitive ;
586- if ( finalPointee . IsPrimitiveType ( out primitive ) || finalPointee . IsEnumType ( ) )
587- {
588- // From MSDN: "note that a ref or out parameter is classified as a moveable
589- // variable". This means we must create a local variable to hold the result
590- // and then assign this value to the parameter.
591-
592- if ( isRefParam )
593- {
594- var typeName = Type . TypePrinterDelegate ( finalPointee ) ;
595- if ( Context . Function . OperatorKind == CXXOperatorKind . Subscript )
596- Context . Return . Write ( param . Name ) ;
597- else
598- {
599- if ( param . IsInOut )
600- Context . Before . WriteLine ( $ "{ typeName } _{ param . Name } = { param . Name } ;") ;
601- else
602- Context . Before . WriteLine ( $ "{ typeName } _{ param . Name } ;") ;
603-
604- Context . Return . Write ( $ "&_{ param . Name } ") ;
605- }
606- }
607- else
608- {
609- if ( Context . Context . Options . MarshalCharAsManagedChar &&
610- primitive == PrimitiveType . Char )
611- Context . Return . Write ( $ "({ typePrinter . PrintNative ( pointer ) } ) ") ;
612-
613- if ( qualifiedPointer . IsConstRefToPrimitive ( ) )
614- {
615- if ( primitive == PrimitiveType . Void && pointee . IsAddress ( ) )
616- {
617- string ptr = $@ "{ Helpers . PtrIdentifier } {
618- Context . ParameterIndex } " ;
619- Context . Before . WriteLine ( $@ "var { ptr } = {
620- Context . Parameter . Name } .ToPointer();" ) ;
621- Context . Return . Write ( $ "&{ ptr } ") ;
622- return true ;
623- }
624- Context . Return . Write ( "&" ) ;
625- }
626- Context . Return . Write ( Context . Parameter . Name ) ;
627- }
628-
629- return true ;
630- }
631-
632589 return pointer . QualifiedPointee . Visit ( this ) ;
633590 }
634591
635592 public override bool VisitPrimitiveType ( PrimitiveType primitive , TypeQualifiers quals )
636593 {
637594 switch ( primitive )
638595 {
639- case PrimitiveType . Void :
640- return true ;
641596 case PrimitiveType . Bool :
642597 if ( Context . MarshalKind == MarshalKind . NativeField )
643598 {
@@ -657,24 +612,21 @@ public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
657612 if ( ! VisitType ( typedef , quals ) )
658613 return false ;
659614
660- var decl = typedef . Declaration ;
661-
662- FunctionType func ;
663- if ( decl . Type . IsPointerTo ( out func ) )
664- {
665- VisitDelegateType ( ) ;
666- return true ;
667- }
668-
669- return decl . Type . Visit ( this ) ;
615+ return typedef . Declaration . Type . Visit ( this ) ;
670616 }
671617
672618 public override bool VisitTemplateParameterSubstitutionType ( TemplateParameterSubstitutionType param , TypeQualifiers quals )
673619 {
674620 var replacement = param . Replacement . Type . Desugar ( ) ;
675- Class @class ;
676- if ( ! replacement . IsAddress ( ) && ! replacement . TryGetClass ( out @class ) )
677- Context . Return . Write ( $ "({ replacement } ) (object) ") ;
621+ if ( replacement . IsPrimitiveType ( ) ||
622+ replacement . IsPointerToPrimitiveType ( ) ||
623+ replacement . IsEnum ( ) )
624+ {
625+ Context . Return . Write ( $ "({ replacement } ) ") ;
626+ if ( replacement . IsPointerToPrimitiveType ( ) )
627+ Context . Return . Write ( $ "({ CSharpTypePrinter . IntPtrType } ) ") ;
628+ Context . Return . Write ( "(object) " ) ;
629+ }
678630 return base . VisitTemplateParameterSubstitutionType ( param , quals ) ;
679631 }
680632
@@ -811,18 +763,18 @@ public override bool VisitClassTemplateDecl(ClassTemplate template)
811763 return VisitClassDecl ( template . TemplatedClass ) ;
812764 }
813765
814- public override bool VisitFunctionTemplateDecl ( FunctionTemplate template )
815- {
816- return template . TemplatedFunction . Visit ( this ) ;
817- }
818-
819- private bool VisitDelegateType ( )
766+ public override bool VisitFunctionType ( FunctionType function , TypeQualifiers quals )
820767 {
821768 Context . Return . Write ( "{0} == null ? global::System.IntPtr.Zero : Marshal.GetFunctionPointerForDelegate({0})" ,
822769 Context . Parameter . Name ) ;
823770 return true ;
824771 }
825772
773+ public override bool VisitFunctionTemplateDecl ( FunctionTemplate template )
774+ {
775+ return template . TemplatedFunction . Visit ( this ) ;
776+ }
777+
826778 private void ThrowArgumentOutOfRangeException ( )
827779 {
828780 Context . Before . WriteLineIndent (
@@ -883,6 +835,17 @@ private void MarshalArray(ArrayType arrayType)
883835 Context . Return . Write ( intermediateArray ) ;
884836 }
885837
838+ private void MarshalString ( Type pointee )
839+ {
840+ var marshal = new CSharpMarshalNativeToManagedPrinter ( Context ) ;
841+ Context . ReturnVarName = Context . ArgName ;
842+ Context . ReturnType = Context . Parameter . QualifiedType ;
843+ pointee . Visit ( marshal ) ;
844+ Context . Cleanup . WriteLine ( $@ "{ Context . Parameter . Name } = {
845+ marshal . Context . Return } ;" ) ;
846+ Context . Return . StringBuilder . Clear ( ) ;
847+ }
848+
886849 private readonly CSharpTypePrinter typePrinter ;
887850 }
888851}
0 commit comments