@@ -161,7 +161,7 @@ public override async Task<CSharpSyntaxNode> VisitNamespaceBlock(VBSyntax.Namesp
161161 {
162162 var members = ( await node . Members . SelectAsync ( ConvertMemberAsync ) ) . Where ( m => m != null ) ;
163163 var sym = ModelExtensions . GetDeclaredSymbol ( _semanticModel , node ) ;
164- string namespaceToDeclare = await WithDeclarationCasingAsync ( node , sym ) ;
164+ string namespaceToDeclare = await WithDeclarationNameCasingAsync ( node , sym ) ;
165165 var parentNamespaceSyntax = node . GetAncestor < VBSyntax . NamespaceBlockSyntax > ( ) ;
166166 var parentNamespaceDecl = parentNamespaceSyntax != null ? ModelExtensions . GetDeclaredSymbol ( _semanticModel , parentNamespaceSyntax ) : null ;
167167 var parentNamespaceFullName = parentNamespaceDecl ? . ToDisplayString ( ) ?? _topAncestorNamespace ;
@@ -174,10 +174,10 @@ public override async Task<CSharpSyntaxNode> VisitNamespaceBlock(VBSyntax.Namesp
174174
175175 /// <summary>
176176 /// Semantic model merges the symbols, but the compiled form retains multiple namespaces, which (when referenced from C#) need to keep the correct casing.
177- /// <seealso cref="CommonConversions.WithDeclarationCasing (TypeSyntax, ITypeSymbol)"/>
178- /// <seealso cref="CommonConversions.WithDeclarationCasing (SyntaxToken, ISymbol, string)"/>
177+ /// <seealso cref="CommonConversions.WithDeclarationNameCasing (TypeSyntax, ITypeSymbol)"/>
178+ /// <seealso cref="CommonConversions.WithDeclarationName (SyntaxToken, ISymbol, string)"/>
179179 /// </summary>
180- private async Task < string > WithDeclarationCasingAsync ( VBSyntax . NamespaceBlockSyntax node , ISymbol sym )
180+ private async Task < string > WithDeclarationNameCasingAsync ( VBSyntax . NamespaceBlockSyntax node , ISymbol sym )
181181 {
182182 var sourceName = ( await node . NamespaceStatement . Name . AcceptAsync ( _triviaConvertingExpressionVisitor ) ) . ToString ( ) ;
183183 var namespaceToDeclare = sym ? . ToDisplayString ( ) ?? sourceName ;
@@ -1034,10 +1034,12 @@ public override async Task<CSharpSyntaxNode> VisitMethodStatement(VBSyntax.Metho
10341034 return decl . WithSemicolonToken ( SemicolonToken ) ;
10351035 } else {
10361036 var tokenContext = GetMemberContext ( node ) ;
1037- var declaredSymbol = ModelExtensions . GetDeclaredSymbol ( _semanticModel , node ) as IMethodSymbol ;
1038- var extraCsModifierKinds = declaredSymbol ? . IsExtern == true ? new [ ] { Microsoft . CodeAnalysis . CSharp . SyntaxKind . ExternKeyword } : Array . Empty < Microsoft . CodeAnalysis . CSharp . SyntaxKind > ( ) ;
1037+ var declaredSymbol = ( IMethodSymbol ) ModelExtensions . GetDeclaredSymbol ( _semanticModel , node ) ;
1038+ var extraCsModifierKinds = declaredSymbol ? . IsExtern == true ? new [ ] { Microsoft . CodeAnalysis . CSharp . SyntaxKind . ExternKeyword } : Array . Empty < Microsoft . CodeAnalysis . CSharp . SyntaxKind > ( ) ;
10391039 var convertedModifiers = CommonConversions . ConvertModifiers ( node , node . Modifiers , tokenContext , extraCsModifierKinds : extraCsModifierKinds ) ;
1040-
1040+ var explicitInterfaceSpecifier = declaredSymbol . DeclaredAccessibility == Accessibility . Private && declaredSymbol . ExplicitInterfaceImplementations . Any ( ) ?
1041+ SyntaxFactory . ExplicitInterfaceSpecifier ( SyntaxFactory . IdentifierName ( declaredSymbol . ExplicitInterfaceImplementations . First ( ) . ContainingType . Name ) )
1042+ : null ;
10411043 bool accessedThroughMyClass = IsAccessedThroughMyClass ( node , node . Identifier , declaredSymbol ) ;
10421044
10431045 var isPartialDefinition = declaredSymbol . IsPartialMethodDefinition ( ) ;
@@ -1053,50 +1055,96 @@ public override async Task<CSharpSyntaxNode> VisitMethodStatement(VBSyntax.Metho
10531055 }
10541056 var ( typeParameters , constraints ) = await SplitTypeParametersAsync ( node . TypeParameterList ) ;
10551057
1058+ var returnType = ( TypeSyntax ) ( declaredSymbol != null ? CommonConversions . GetTypeSyntax ( declaredSymbol . ReturnType ) :
1059+ await ( node . AsClause ? . Type ) . AcceptAsync ( _triviaConvertingExpressionVisitor ) ?? SyntaxFactory . PredefinedType ( SyntaxFactory . Token ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . VoidKeyword ) ) ) ;
1060+
1061+ var directlyConvertedCsIdentifier = CommonConversions . CsEscapedIdentifier ( node . Identifier . Value as string ) ;
10561062 var csIdentifier = CommonConversions . ConvertIdentifier ( node . Identifier ) ;
1063+ var parameterList = ( ParameterListSyntax ) await node . ParameterList . AcceptAsync ( _triviaConvertingExpressionVisitor ) ?? SyntaxFactory . ParameterList ( ) ;
1064+ var additionalDeclarations = new List < MemberDeclarationSyntax > ( ) ;
1065+
1066+ // If we had to rename the method to match the interface, emit a method for external references with the old name to point to
1067+ if ( ! StringComparer . OrdinalIgnoreCase . Equals ( directlyConvertedCsIdentifier . Value , csIdentifier . Value ) && declaredSymbol . GetResultantVisibility ( ) == SymbolVisibility . Public ) {
1068+
1069+ var arrowClause = SyntaxFactory . ArrowExpressionClause ( SyntaxFactory . InvocationExpression ( SyntaxFactory . IdentifierName ( csIdentifier ) , CreateDelegatingArgList ( parameterList ) ) ) ;
1070+ additionalDeclarations . Add ( SyntaxFactory . MethodDeclaration (
1071+ attributes ,
1072+ convertedModifiers ,
1073+ returnType ,
1074+ explicitInterfaceSpecifier ,
1075+ directlyConvertedCsIdentifier ,
1076+ typeParameters ,
1077+ parameterList ,
1078+ constraints ,
1079+ null ,
1080+ arrowClause ,
1081+ SyntaxFactory . Token ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . SemicolonToken )
1082+ ) ) ;
1083+ }
10571084 // If the method is virtual, and there is a MyClass.SomeMethod() call,
10581085 // we need to emit a non-virtual method for it to call
1059- var returnType = ( TypeSyntax ) ( declaredSymbol != null ? CommonConversions . GetTypeSyntax ( declaredSymbol . ReturnType ) :
1060- await ( node . AsClause ? . Type ) . AcceptAsync ( _triviaConvertingExpressionVisitor ) ?? SyntaxFactory . PredefinedType ( SyntaxFactory . Token ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . VoidKeyword ) ) ) ;
1061- if ( accessedThroughMyClass )
1062- {
1086+ if ( accessedThroughMyClass ) {
10631087 var identifierName = "MyClass" + csIdentifier . ValueText ;
1064- var arrowClause = SyntaxFactory . ArrowExpressionClause ( SyntaxFactory . InvocationExpression ( SyntaxFactory . IdentifierName ( identifierName ) ) ) ;
1065- var realDecl = SyntaxFactory . MethodDeclaration (
1088+ var arrowClause = SyntaxFactory . ArrowExpressionClause ( SyntaxFactory . InvocationExpression ( SyntaxFactory . IdentifierName ( identifierName ) , CreateDelegatingArgList ( parameterList ) ) ) ;
1089+
1090+ convertedModifiers = convertedModifiers . RemoveOnly ( m => m . IsKind ( CSSyntaxKind . PrivateKeyword ) ) ;
1091+ var originalNameDecl = SyntaxFactory . MethodDeclaration (
10661092 attributes ,
10671093 convertedModifiers ,
10681094 returnType ,
1069- null , CommonConversions . ConvertIdentifier ( node . Identifier ) ,
1095+ explicitInterfaceSpecifier ,
1096+ csIdentifier ,
10701097 typeParameters ,
1071- ( ParameterListSyntax ) await node . ParameterList . AcceptAsync ( _triviaConvertingExpressionVisitor , SourceTriviaMapKind . None ) ?? SyntaxFactory . ParameterList ( ) ,
1098+ parameterList ,
10721099 constraints ,
10731100 null ,
10741101 arrowClause ,
1075- SyntaxFactory . Token ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . SemicolonToken )
1102+ SyntaxFactory . Token ( CSSyntaxKind . SemicolonToken )
10761103 ) ;
10771104
1078- var declNode = ( VBSyntax . StatementSyntax ) node . Parent ;
1079- _additionalDeclarations . Add ( declNode , new MemberDeclarationSyntax [ ] { realDecl } ) ;
1080- convertedModifiers = convertedModifiers . Remove ( convertedModifiers . Single ( m => m . IsKind ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . VirtualKeyword ) ) ) ;
1105+ additionalDeclarations . Add ( originalNameDecl ) ;
1106+ convertedModifiers = convertedModifiers . Remove ( convertedModifiers . Single ( m => m . IsKind ( CSSyntaxKind . VirtualKeyword ) ) ) ;
10811107 csIdentifier = SyntaxFactory . Identifier ( identifierName ) ;
1108+ explicitInterfaceSpecifier = null ;
1109+ } else if ( explicitInterfaceSpecifier != null ) {
1110+ convertedModifiers = convertedModifiers . Remove ( convertedModifiers . Single ( m => m . IsKind ( CSSyntaxKind . PrivateKeyword ) ) ) ;
1111+ }
1112+
1113+ if ( additionalDeclarations . Any ( ) ) {
1114+ var declNode = ( VBSyntax . StatementSyntax ) node . Parent ;
1115+ _additionalDeclarations . Add ( declNode , additionalDeclarations . ToArray ( ) ) ;
10821116 }
10831117
10841118 var decl = SyntaxFactory . MethodDeclaration (
10851119 attributes ,
10861120 convertedModifiers ,
10871121 returnType ,
1088- null ,
1122+ explicitInterfaceSpecifier ,
10891123 csIdentifier ,
10901124 typeParameters ,
1091- ( ParameterListSyntax ) await node . ParameterList . AcceptAsync ( _triviaConvertingExpressionVisitor ) ?? SyntaxFactory . ParameterList ( ) ,
1125+ parameterList ,
10921126 constraints ,
1093- null ,
1127+ null , //Body added by surrounding method block if appropriate
10941128 null
10951129 ) ;
10961130 return hasBody && declaredSymbol . CanHaveMethodBody ( ) ? decl : decl . WithSemicolonToken ( SemicolonToken ) ;
10971131 }
10981132 }
10991133
1134+ private static ArgumentListSyntax CreateDelegatingArgList ( ParameterListSyntax parameterList )
1135+ {
1136+ var refKinds = parameterList . Parameters . Select ( GetSingleModifier ) . ToArray ( ) ;
1137+ return parameterList . Parameters . Select ( p => SyntaxFactory . IdentifierName ( p . Identifier ) ) . CreateCsArgList ( refKinds ) ;
1138+ }
1139+
1140+ private static CSSyntaxKind ? GetSingleModifier ( ParameterSyntax p )
1141+ {
1142+ var argKinds = new CSSyntaxKind ? [ ] { CSSyntaxKind . RefKeyword , CSSyntaxKind . OutKeyword , CSSyntaxKind . InKeyword } ;
1143+ return p . Modifiers . Select ( Microsoft . CodeAnalysis . CSharp . CSharpExtensions . Kind )
1144+ . Select < CSSyntaxKind , CSSyntaxKind ? > ( k => k )
1145+ . FirstOrDefault ( argKinds . Contains ) ;
1146+ }
1147+
11001148 private TokenContext GetMemberContext ( VBSyntax . StatementSyntax member )
11011149 {
11021150 var parentType = member . GetAncestorOrThis < VBSyntax . TypeBlockSyntax > ( ) ;
0 commit comments