@@ -679,15 +679,20 @@ string GetCSharpIdentifierText(VBSyntax.EventContainerSyntax p)
679679
680680 public override async Task < CSharpSyntaxNode > VisitPropertyStatement ( VBSyntax . PropertyStatementSyntax node )
681681 {
682- var attributes = await node . AttributeLists . SelectManyAsync ( CommonConversions . ConvertAttributeAsync ) ;
682+ var attributes = SyntaxFactory . List ( await node . AttributeLists . SelectManyAsync ( CommonConversions . ConvertAttributeAsync ) ) ;
683683 var isReadonly = node . Modifiers . Any ( m => SyntaxTokenExtensions . IsKind ( m , VBasic . SyntaxKind . ReadOnlyKeyword ) ) ;
684684 var isWriteOnly = node . Modifiers . Any ( m => SyntaxTokenExtensions . IsKind ( m , VBasic . SyntaxKind . WriteOnlyKeyword ) ) ;
685685 var convertibleModifiers = node . Modifiers . Where ( m => ! m . IsKind ( VBasic . SyntaxKind . ReadOnlyKeyword , VBasic . SyntaxKind . WriteOnlyKeyword , VBasic . SyntaxKind . DefaultKeyword ) ) ;
686686 var modifiers = CommonConversions . ConvertModifiers ( node , convertibleModifiers . ToList ( ) , GetMemberContext ( node ) ) ;
687687 var isIndexer = CommonConversions . IsDefaultIndexer ( node ) ;
688- var nodeSymbol = ModelExtensions . GetDeclaredSymbol ( _semanticModel , node ) ;
689- var accessedThroughMyClass = IsAccessedThroughMyClass ( node , node . Identifier , nodeSymbol ) ;
688+ var propSymbol = ModelExtensions . GetDeclaredSymbol ( _semanticModel , node ) as IPropertySymbol ;
689+ var accessedThroughMyClass = IsAccessedThroughMyClass ( node , node . Identifier , propSymbol ) ;
690690 bool hasImplementation = ! node . Modifiers . Any ( m => m . IsKind ( VBasic . SyntaxKind . MustOverrideKeyword ) ) && node . GetAncestor < VBSyntax . InterfaceBlockSyntax > ( ) == null ;
691+ var explicitInterfaceSpecifier = propSymbol . DeclaredAccessibility == Accessibility . Private && propSymbol . ExplicitInterfaceImplementations . Any ( ) ?
692+ SyntaxFactory . ExplicitInterfaceSpecifier ( SyntaxFactory . IdentifierName ( propSymbol . ExplicitInterfaceImplementations . First ( ) . ContainingType . Name ) )
693+ : null ;
694+ var shouldConvertToMethods = await ShouldConvertAsParameterizedPropertyAsync ( node ) ;
695+
691696
692697 var initializer = ( EqualsValueClauseSyntax ) await node . Initializer . AcceptAsync ( _triviaConvertingExpressionVisitor ) ;
693698 VBSyntax . TypeSyntax vbType ;
@@ -711,14 +716,13 @@ public override async Task<CSharpSyntaxNode> VisitPropertyStatement(VBSyntax.Pro
711716
712717 AccessorListSyntax accessors = null ;
713718 if ( node . Parent is VBSyntax . PropertyBlockSyntax propertyBlock ) {
714- if ( node . ParameterList ? . Parameters . Any ( ) == true && ! isIndexer ) {
719+ if ( shouldConvertToMethods ) {
715720 if ( accessedThroughMyClass ) {
716721 // Would need to create a delegating implementation to implement this
717722 throw new NotImplementedException ( "MyClass indexing not implemented" ) ;
718723 }
719-
720724 var methodDeclarationSyntaxs = await propertyBlock . Accessors . SelectAsync ( async a =>
721- ( MethodDeclarationSyntax ) await a . AcceptAsync ( TriviaConvertingDeclarationVisitor ) ) ;
725+ ( MethodDeclarationSyntax ) await a . AcceptAsync ( TriviaConvertingDeclarationVisitor , a == propertyBlock . Accessors . First ( ) ? SourceTriviaMapKind . All : SourceTriviaMapKind . None ) ) ;
722726 var accessorMethods = methodDeclarationSyntaxs . Select ( WithMergedModifiers ) . ToArray ( ) ;
723727 _additionalDeclarations . Add ( propertyBlock , accessorMethods . Skip ( 1 ) . ToArray ( ) ) ;
724728 return accessorMethods [ 0 ] ;
@@ -727,11 +731,24 @@ public override async Task<CSharpSyntaxNode> VisitPropertyStatement(VBSyntax.Pro
727731 accessors = SyntaxFactory . AccessorList (
728732 SyntaxFactory . List (
729733 ( await propertyBlock . Accessors . SelectAsync ( async a =>
730- ( AccessorDeclarationSyntax ) await a . AcceptAsync ( TriviaConvertingDeclarationVisitor ) )
734+ ( AccessorDeclarationSyntax ) await a . AcceptAsync ( TriviaConvertingDeclarationVisitor ) )
731735 )
732736 ) ) ;
737+ } else if ( shouldConvertToMethods && propSymbol . ContainingType . IsInterfaceType ( ) ) {
738+ var methodDeclarationSyntaxs = new List < MemberDeclarationSyntax > ( ) ;
739+ if ( propSymbol . GetMethod != null ) {
740+ methodDeclarationSyntaxs . Add ( await CreateMethodDeclarationSyntaxAsync ( node . ParameterList , GetMethodId ( node ) , false ) ) ;
741+ }
742+ if ( propSymbol . SetMethod != null ) {
743+ var setMethod = await CreateMethodDeclarationSyntaxAsync ( node . ParameterList , SetMethodId ( node ) , true ) ;
744+ var valueParam = SyntaxFactory . Parameter ( CommonConversions . CsEscapedIdentifier ( "value" ) ) . WithType ( rawType ) ;
745+ setMethod = setMethod . AddParameterListParameters ( valueParam ) ;
746+ methodDeclarationSyntaxs . Add ( setMethod ) ;
747+ }
748+ _additionalDeclarations . Add ( node , methodDeclarationSyntaxs . Skip ( 1 ) . ToArray ( ) ) ;
749+ return methodDeclarationSyntaxs [ 0 ] ;
733750 } else {
734- accessors = ConvertSimpleAccessors ( isWriteOnly , isReadonly , hasImplementation , nodeSymbol . DeclaredAccessibility ) ;
751+ accessors = ConvertSimpleAccessors ( isWriteOnly , isReadonly , hasImplementation , propSymbol . DeclaredAccessibility ) ;
735752 }
736753
737754
@@ -755,17 +772,21 @@ public override async Task<CSharpSyntaxNode> VisitPropertyStatement(VBSyntax.Pro
755772 var csIdentifier = CommonConversions . ConvertIdentifier ( node . Identifier ) ;
756773
757774 if ( accessedThroughMyClass ) {
758- string csIndentifierName = AddRealPropertyDelegatingToMyClassVersion ( node , csIdentifier , attributes , modifiers , rawType ) ;
775+
776+ var realModifiers = modifiers . RemoveOnly ( m => m . IsKind ( CSSyntaxKind . PrivateKeyword ) ) ;
777+ string csIndentifierName = AddRealPropertyDelegatingToMyClassVersion ( node , csIdentifier , attributes , realModifiers , rawType ) ;
759778 modifiers = modifiers . Remove ( modifiers . Single ( m => m . IsKind ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . VirtualKeyword ) ) ) ;
760779 csIdentifier = SyntaxFactory . Identifier ( csIndentifierName ) ;
780+ } else if ( explicitInterfaceSpecifier != null ) {
781+ modifiers = modifiers . RemoveOnly ( m => m . IsKind ( CSSyntaxKind . PrivateKeyword ) ) ;
761782 }
762783
763784 var semicolonToken = SyntaxFactory . Token ( initializer == null ? Microsoft . CodeAnalysis . CSharp . SyntaxKind . None : Microsoft . CodeAnalysis . CSharp . SyntaxKind . SemicolonToken ) ;
764785 return SyntaxFactory . PropertyDeclaration (
765- SyntaxFactory . List ( attributes ) ,
786+ attributes ,
766787 modifiers ,
767788 rawType ,
768- null ,
789+ explicitInterfaceSpecifier ,
769790 csIdentifier , accessors ,
770791 null ,
771792 initializer ,
@@ -777,24 +798,39 @@ MemberDeclarationSyntax WithMergedModifiers(MethodDeclarationSyntax member)
777798 SyntaxTokenList originalModifiers = member . GetModifiers ( ) ;
778799 var hasVisibility = originalModifiers . Any ( m => m . IsCsVisibility ( false , false ) ) ;
779800 var modifiersToAdd = hasVisibility ? modifiers . Where ( m => ! m . IsCsVisibility ( false , false ) ) : modifiers ;
780- return member . WithModifiers ( SyntaxFactory . TokenList ( originalModifiers . Concat ( modifiersToAdd ) ) ) ;
801+ var newModifiers = SyntaxFactory . TokenList ( originalModifiers . Concat ( modifiersToAdd ) ) ;
802+ if ( explicitInterfaceSpecifier != null ) newModifiers = SyntaxFactory . TokenList ( newModifiers . Where ( m => ! m . IsCsVisibility ( false , false ) ) ) ;
803+ return member . WithModifiers ( newModifiers ) ;
804+ }
805+
806+ async Task < MethodDeclarationSyntax > CreateMethodDeclarationSyntaxAsync ( VBSyntax . ParameterListSyntax containingPropParameterList , string methodId , bool voidReturn )
807+ {
808+ var parameterListSyntax = ( ParameterListSyntax ) await containingPropParameterList . AcceptAsync ( _triviaConvertingExpressionVisitor ) ;
809+ var methodModifiers = SyntaxFactory . TokenList ( modifiers . Where ( m => ! m . IsCsVisibility ( false , false ) ) ) ;
810+ MethodDeclarationSyntax methodDeclarationSyntax = SyntaxFactory . MethodDeclaration ( attributes , methodModifiers ,
811+ voidReturn ? SyntaxFactory . PredefinedType ( SyntaxFactory . Token ( CSSyntaxKind . VoidKeyword ) ) : rawType ,
812+ explicitInterfaceSpecifier ,
813+ SyntaxFactory . Identifier ( methodId ) , null ,
814+ ( ParameterListSyntax ) parameterListSyntax , SyntaxFactory . List < TypeParameterConstraintClauseSyntax > ( ) , null , null )
815+ . WithSemicolonToken ( SyntaxFactory . Token ( CSSyntaxKind . SemicolonToken ) ) ;
816+ return methodDeclarationSyntax ;
781817 }
782818 }
783819
784820 private string AddRealPropertyDelegatingToMyClassVersion ( VBSyntax . PropertyStatementSyntax node , SyntaxToken csIdentifier ,
785- AttributeListSyntax [ ] attributes , SyntaxTokenList modifiers , TypeSyntax rawType )
821+ SyntaxList < AttributeListSyntax > attributes , SyntaxTokenList modifiers , TypeSyntax rawType )
786822 {
787823 var csIndentifierName = "MyClass" + csIdentifier . ValueText ;
788824 ExpressionSyntax thisDotIdentifier = SyntaxFactory . ParseExpression ( $ "this.{ csIndentifierName } ") ;
789825 var getReturn = SyntaxFactory . Block ( SyntaxFactory . ReturnStatement ( thisDotIdentifier ) ) ;
790826 var getAccessor = SyntaxFactory . AccessorDeclaration ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . GetAccessorDeclaration , getReturn ) ;
791827 var setValue = SyntaxFactory . Block ( SyntaxFactory . ExpressionStatement (
792828 SyntaxFactory . AssignmentExpression ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . SimpleAssignmentExpression , thisDotIdentifier ,
793- SyntaxFactory . IdentifierName ( "value" ) ) ) ) ;
829+ SyntaxFactory . IdentifierName ( CommonConversions . CsEscapedIdentifier ( "value" ) ) ) ) ) ;
794830 var setAccessor = SyntaxFactory . AccessorDeclaration ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . SetAccessorDeclaration , setValue ) ;
795831 var realAccessors = SyntaxFactory . AccessorList ( SyntaxFactory . List ( new [ ] { getAccessor , setAccessor } ) ) ;
796832 var realDecl = SyntaxFactory . PropertyDeclaration (
797- SyntaxFactory . List ( attributes ) ,
833+ attributes ,
798834 modifiers ,
799835 rawType ,
800836 null ,
@@ -851,34 +887,40 @@ public override async Task<CSharpSyntaxNode> VisitAccessorBlock(VBSyntax.Accesso
851887 {
852888 Microsoft . CodeAnalysis . CSharp . SyntaxKind blockKind ;
853889 bool isIterator = node . IsIterator ( ) ;
890+ var ancestoryPropertyBlock = node . GetAncestor < VBSyntax . PropertyBlockSyntax > ( ) ;
891+ var containingPropertyStmt = ancestoryPropertyBlock ? . PropertyStatement ;
854892 var csReturnVariableOrNull = CommonConversions . GetRetVariableNameOrNull ( node ) ;
855893 var convertedStatements = await ConvertStatementsAsync ( node . Statements , await CreateMethodBodyVisitorAsync ( node , isIterator ) ) ;
856894 var body = WithImplicitReturnStatements ( node , convertedStatements , csReturnVariableOrNull ) ;
857895 var attributes = await CommonConversions . ConvertAttributesAsync ( node . AccessorStatement . AttributeLists ) ;
858896 var modifiers = CommonConversions . ConvertModifiers ( node , node . AccessorStatement . Modifiers , TokenContext . Local ) ;
859897 string potentialMethodId ;
860- var ancestoryPropertyBlock = node . GetAncestor < VBSyntax . PropertyBlockSyntax > ( ) ;
861- var containingPropertyStmt = ancestoryPropertyBlock ? . PropertyStatement ;
898+ var declaredParentSymbol = containingPropertyStmt != null ? _semanticModel . GetDeclaredSymbol ( containingPropertyStmt ) : null ;
899+ var explicitInterfaceSpecifier = declaredParentSymbol is IPropertySymbol propSymbol && propSymbol . DeclaredAccessibility == Accessibility . Private && propSymbol . ExplicitInterfaceImplementations . Any ( ) ?
900+ SyntaxFactory . ExplicitInterfaceSpecifier ( SyntaxFactory . IdentifierName ( propSymbol . ExplicitInterfaceImplementations . First ( ) . ContainingType . Name ) )
901+ : null ;
862902 var sourceMap = ancestoryPropertyBlock ? . Accessors . FirstOrDefault ( ) == node ? SourceTriviaMapKind . All : SourceTriviaMapKind . None ;
903+ var returnType = containingPropertyStmt ? . AsClause is VBSyntax . SimpleAsClauseSyntax asClause ?
904+ await asClause . Type . AcceptAsync < TypeSyntax > ( _triviaConvertingExpressionVisitor , sourceMap ) :
905+ SyntaxFactory . PredefinedType ( SyntaxFactory . Token ( CSSyntaxKind . VoidKeyword ) ) ;
906+
863907 switch ( node . Kind ( ) ) {
864908 case VBasic . SyntaxKind . GetAccessorBlock :
865909 blockKind = Microsoft . CodeAnalysis . CSharp . SyntaxKind . GetAccessorDeclaration ;
866- potentialMethodId = $ "get_ { ( containingPropertyStmt . Identifier . Text ) } " ;
910+ potentialMethodId = GetMethodId ( containingPropertyStmt ) ;
867911
868- if ( containingPropertyStmt . AsClause is VBSyntax . SimpleAsClauseSyntax getAsClause &&
869- await ShouldConvertAsParameterizedProperty ( ) ) {
870- var method = await CreateMethodDeclarationSyntax ( containingPropertyStmt ? . ParameterList ) ;
871- return method . WithReturnType ( ( TypeSyntax ) await getAsClause . Type . AcceptAsync ( _triviaConvertingExpressionVisitor , sourceMap ) ) ;
912+ if ( await ShouldConvertAsParameterizedPropertyAsync ( containingPropertyStmt ) ) {
913+ var method = await CreateMethodDeclarationSyntax ( containingPropertyStmt ? . ParameterList , false ) ;
914+ return method ;
872915 }
873916 break ;
874917 case VBasic . SyntaxKind . SetAccessorBlock :
875918 blockKind = Microsoft . CodeAnalysis . CSharp . SyntaxKind . SetAccessorDeclaration ;
876- potentialMethodId = $ "set_ { ( containingPropertyStmt . Identifier . Text ) } " ;
919+ potentialMethodId = SetMethodId ( containingPropertyStmt ) ;
877920
878- if ( containingPropertyStmt . AsClause is VBSyntax . SimpleAsClauseSyntax setAsClause && await ShouldConvertAsParameterizedProperty ( ) ) {
879- var setMethod = await CreateMethodDeclarationSyntax ( containingPropertyStmt ? . ParameterList ) ;
880- var valueParameterType = ( TypeSyntax ) await setAsClause . Type . AcceptAsync ( _triviaConvertingExpressionVisitor , sourceMap ) ;
881- return setMethod . AddParameterListParameters ( SyntaxFactory . Parameter ( SyntaxFactory . Identifier ( "value" ) ) . WithType ( valueParameterType ) ) ;
921+ if ( await ShouldConvertAsParameterizedPropertyAsync ( containingPropertyStmt ) ) {
922+ var setMethod = await CreateMethodDeclarationSyntax ( containingPropertyStmt ? . ParameterList , true ) ;
923+ return setMethod . AddParameterListParameters ( SyntaxFactory . Parameter ( CommonConversions . CsEscapedIdentifier ( "value" ) ) . WithType ( returnType ) ) ;
882924 }
883925 break ;
884926 case VBasic . SyntaxKind . AddHandlerAccessorBlock :
@@ -891,33 +933,46 @@ await ShouldConvertAsParameterizedProperty()) {
891933 var eventStatement = ( ( VBSyntax . EventBlockSyntax ) node . Parent ) . EventStatement ;
892934 var eventName = CommonConversions . ConvertIdentifier ( eventStatement . Identifier ) . ValueText ;
893935 potentialMethodId = $ "On{ eventName } ";
894- return await CreateMethodDeclarationSyntax ( node . AccessorStatement . ParameterList ) ;
936+ return await CreateMethodDeclarationSyntax ( node . AccessorStatement . ParameterList , true ) ;
895937 default :
896938 throw new NotSupportedException ( node . Kind ( ) . ToString ( ) ) ;
897939 }
898940
899941 return SyntaxFactory . AccessorDeclaration ( blockKind , attributes , modifiers , body ) ;
900942
901- async Task < bool > ShouldConvertAsParameterizedProperty ( )
902- {
903- if ( containingPropertyStmt . ParameterList ? . Parameters . Any ( ) == true && ! CommonConversions . IsDefaultIndexer ( containingPropertyStmt ) ) {
904- return true ;
905- }
906-
907- return false ;
908- }
909-
910- async Task < MethodDeclarationSyntax > CreateMethodDeclarationSyntax ( VBSyntax . ParameterListSyntax containingPropParameterList )
943+ async Task < MethodDeclarationSyntax > CreateMethodDeclarationSyntax ( VBSyntax . ParameterListSyntax containingPropParameterList , bool voidReturn )
911944 {
912945 var parameterListSyntax = await containingPropParameterList . AcceptAsync ( _triviaConvertingExpressionVisitor , sourceMap ) ;
913- MethodDeclarationSyntax methodDeclarationSyntax = SyntaxFactory . MethodDeclaration ( attributes , modifiers ,
914- SyntaxFactory . PredefinedType ( SyntaxFactory . Token ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . VoidKeyword ) ) , null ,
946+ var methodModifiers = explicitInterfaceSpecifier != null ? modifiers . RemoveOnly ( x => x . IsKind ( CSSyntaxKind . PrivateKeyword ) )
947+ : modifiers ;
948+ MethodDeclarationSyntax methodDeclarationSyntax = SyntaxFactory . MethodDeclaration ( attributes , methodModifiers ,
949+ voidReturn ? SyntaxFactory . PredefinedType ( SyntaxFactory . Token ( CSSyntaxKind . VoidKeyword ) ) : returnType ,
950+ explicitInterfaceSpecifier ,
915951 SyntaxFactory . Identifier ( potentialMethodId ) , null ,
916- ( ParameterListSyntax ) parameterListSyntax , SyntaxFactory . List < TypeParameterConstraintClauseSyntax > ( ) , body , null ) ;
952+ ( ParameterListSyntax ) parameterListSyntax , SyntaxFactory . List < TypeParameterConstraintClauseSyntax > ( ) , body , null ) ;
917953 return methodDeclarationSyntax ;
918954 }
919955 }
920956
957+ private static string SetMethodId ( VBSyntax . PropertyStatementSyntax containingPropertyStmt )
958+ {
959+ return $ "set_{ ( containingPropertyStmt . Identifier . Text ) } ";
960+ }
961+
962+ private static string GetMethodId ( VBSyntax . PropertyStatementSyntax containingPropertyStmt )
963+ {
964+ return $ "get_{ ( containingPropertyStmt . Identifier . Text ) } ";
965+ }
966+
967+ private async Task < bool > ShouldConvertAsParameterizedPropertyAsync ( VBSyntax . PropertyStatementSyntax propStmt )
968+ {
969+ if ( propStmt . ParameterList ? . Parameters . Any ( ) == true && ! CommonConversions . IsDefaultIndexer ( propStmt ) ) {
970+ return true ;
971+ }
972+
973+ return false ;
974+ }
975+
921976 public override async Task < CSharpSyntaxNode > VisitAccessorStatement ( VBSyntax . AccessorStatementSyntax node )
922977 {
923978 return SyntaxFactory . AccessorDeclaration ( node . Kind ( ) . ConvertToken ( ) , null ) ;
@@ -1079,7 +1134,7 @@ public override async Task<CSharpSyntaxNode> VisitMethodStatement(VBSyntax.Metho
10791134 null ,
10801135 arrowClause ,
10811136 SyntaxFactory . Token ( Microsoft . CodeAnalysis . CSharp . SyntaxKind . SemicolonToken )
1082- ) ) ;
1137+ ) . WithoutSourceMapping ( ) ) ;
10831138 }
10841139 // If the method is virtual, and there is a MyClass.SomeMethod() call,
10851140 // we need to emit a non-virtual method for it to call
0 commit comments