11using System ;
22using System . Collections . Generic ;
3+ using System . Collections . Immutable ;
34using System . Linq ;
45using ICSharpCode . CodeConverter . Shared ;
56using ICSharpCode . CodeConverter . Util ;
@@ -50,6 +51,7 @@ internal class NodesVisitor : CS.CSharpSyntaxVisitor<VisualBasicSyntaxNode>
5051 private readonly HashSet < string > _extraImports = new HashSet < string > ( ) ;
5152 private readonly CSharpHelperMethodDefinition _cSharpHelperMethodDefinition ;
5253 private readonly CommonConversions _commonConversions ;
54+ private readonly HashSet < string > _addedNames = new HashSet < string > ( ) ;
5355
5456 private int _placeholder = 1 ;
5557 public CommentConvertingVisitorWrapper < VisualBasicSyntaxNode > TriviaConvertingVisitor { get ; }
@@ -432,7 +434,7 @@ public override VisualBasicSyntaxNode VisitMethodDeclaration(CSS.MethodDeclarati
432434 if ( needsOverloads == true ) {
433435 modifiers = modifiers . Add ( SyntaxFactory . Token ( SyntaxKind . OverloadsKeyword ) ) ;
434436 }
435- var implementsClause = methodInfo == null ? null : CreateImplementsClauseSyntaxOrNull ( methodInfo , id ) ;
437+ var implementsClause = methodInfo == null ? null : CreateImplementsClauseSyntaxOrNull ( methodInfo , ref id ) ;
436438 if ( isVoidSub ) {
437439 var stmt = SyntaxFactory . SubStatement (
438440 attributes ,
@@ -459,20 +461,33 @@ public override VisualBasicSyntaxNode VisitMethodDeclaration(CSS.MethodDeclarati
459461 /// <remarks>
460462 /// PERF: Computational complexity high due to starting with all members and narrowing down
461463 /// </remarks>
462- private ImplementsClauseSyntax CreateImplementsClauseSyntaxOrNull ( ISymbol memberInfo , SyntaxToken id )
464+ private ImplementsClauseSyntax CreateImplementsClauseSyntaxOrNull ( ISymbol memberInfo , ref SyntaxToken id )
463465 {
466+ var originalId = id ;
464467 var explicitImplementors = memberInfo . ExplicitInterfaceImplementations ( ) ;
465- if ( explicitImplementors . Any ( ) )
466- return CreateImplementsClauseSyntax ( explicitImplementors , id ) ;
467- var containingType = memberInfo . ContainingType ;
468- var baseClassesAndInterfaces = containingType . GetAllBaseClassesAndInterfaces ( true ) ;
469- var implementors = baseClassesAndInterfaces . Except ( new [ ] { containingType } )
470- . SelectMany ( t => t . GetMembers ( ) . Where ( m => memberInfo . Name . EndsWith ( m . Name ) ) )
471- . Where ( m => containingType . FindImplementationForInterfaceMember ( m ) ? . Equals ( memberInfo ) == true )
472- . ToList ( ) ;
468+ if ( explicitImplementors . Any ( ) ) {
469+ //https://github.com/icsharpcode/CodeConverter/issues/492
470+ var memberNames = memberInfo . ContainingType . GetMembers ( ) . ToLookup ( s => UndottedMemberName ( s . Name ) , StringComparer . OrdinalIgnoreCase ) ;
471+ string explicitMemberName = UndottedMemberName ( memberInfo . Name ) ;
472+ var hasDuplicateNames = memberNames [ explicitMemberName ] . Count ( ) > 1 ;
473+ if ( hasDuplicateNames ) id = SyntaxFactory . Identifier ( NameGenerator . GenerateUniqueName ( explicitMemberName , n => ! memberNames . Contains ( n ) && _addedNames . Add ( n ) ) ) ;
474+ } else {
475+ var containingType = memberInfo . ContainingType ;
476+ var baseClassesAndInterfaces = containingType . GetAllBaseClassesAndInterfaces ( true ) ;
477+ explicitImplementors = baseClassesAndInterfaces . Except ( new [ ] { containingType } )
478+ . SelectMany ( t => t . GetMembers ( ) . Where ( m => memberInfo . Name . EndsWith ( m . Name ) ) )
479+ . Where ( m => containingType . FindImplementationForInterfaceMember ( m ) ? . Equals ( memberInfo ) == true )
480+ . ToImmutableArray ( ) ;
481+ }
482+
483+ return ! explicitImplementors . Any ( ) ? null : CreateImplementsClauseSyntax ( explicitImplementors , originalId ) ;
484+ }
473485
474- return ! implementors . Any ( ) ? null : CreateImplementsClauseSyntax ( implementors , id ) ;
486+ private static string UndottedMemberName ( string n )
487+ {
488+ return n . Split ( '.' ) . Last ( ) ;
475489 }
490+
476491 private ImplementsClauseSyntax CreateImplementsClauseSyntax ( IEnumerable < ISymbol > implementors , SyntaxToken id ) {
477492 return SyntaxFactory . ImplementsClause ( implementors . Select ( x => {
478493 NameSyntax nameSyntax = _commonConversions . GetFullyQualifiedNameSyntax ( x . ContainingSymbol as INamedTypeSymbol ) ;
@@ -515,14 +530,15 @@ private VisualBasicSyntaxNode ConvertPropertyBlock(CSS.BasePropertyDeclarationSy
515530 IPropertySymbol declaredSymbol = _semanticModel . GetDeclaredSymbol ( node ) as IPropertySymbol ;
516531 modifiers = modifiers . AddRange ( GetAccessLimitationSyntaxKinds ( declaredSymbol ) . Select ( x => SyntaxFactory . Token ( x ) ) ) ;
517532 Func < PropertyStatementSyntax > getStatementSyntax = ( ) => {
533+ var implementsClauseSyntaxOrNull = declaredSymbol == null ? null : CreateImplementsClauseSyntaxOrNull ( declaredSymbol , ref id ) ;
518534 return SyntaxFactory . PropertyStatement (
519535 attributes ,
520536 modifiers ,
521537 id ,
522538 parameterListSyntax ,
523539 SyntaxFactory . SimpleAsClause ( returnAttributes , ( TypeSyntax ) node . Type . Accept ( TriviaConvertingVisitor ) ) ,
524540 initializerOrNull ,
525- declaredSymbol == null ? null : CreateImplementsClauseSyntaxOrNull ( declaredSymbol , id )
541+ implementsClauseSyntaxOrNull
526542 ) ;
527543 } ;
528544
@@ -591,10 +607,11 @@ public override VisualBasicSyntaxNode VisitEventDeclaration(CSS.EventDeclaration
591607 var id = _commonConversions . ConvertIdentifier ( node . Identifier ) ;
592608 var modifiers = CommonConversions . ConvertModifiers ( node . Modifiers , GetMemberContext ( node ) )
593609 . Add ( SyntaxFactory . Token ( SyntaxKind . CustomKeyword ) ) ;
610+ var implementsClauseSyntaxOrNull = declaredSymbol == null ? null : CreateImplementsClauseSyntaxOrNull ( declaredSymbol , ref id ) ;
594611 var stmt = SyntaxFactory . EventStatement (
595612 attributes , modifiers , id , null ,
596613 SyntaxFactory . SimpleAsClause ( returnAttributes , ( TypeSyntax ) node . Type . Accept ( TriviaConvertingVisitor ) ) ,
597- declaredSymbol == null ? null : CreateImplementsClauseSyntaxOrNull ( declaredSymbol , id )
614+ implementsClauseSyntaxOrNull
598615 ) ;
599616 if ( ! RequiresAccessorBody ( node . AccessorList ) )
600617 return stmt ;
@@ -650,14 +667,15 @@ public override VisualBasicSyntaxNode VisitEventFieldDeclaration(CSS.EventFieldD
650667 var id = SyntaxFactory . Identifier ( decl . Identifier . ValueText , SyntaxFacts . IsKeywordKind ( decl . Identifier . Kind ( ) ) , decl . Identifier . GetIdentifierText ( ) , TypeCharacter . None ) ;
651668 ConvertAndSplitAttributes ( node . AttributeLists , out SyntaxList < AttributeListSyntax > attributes , out SyntaxList < AttributeListSyntax > returnAttributes ) ;
652669 var declaredSymbol = _semanticModel . GetDeclaredSymbol ( decl ) ;
670+ var implementsClauseSyntaxOrNull = declaredSymbol == null ? null : CreateImplementsClauseSyntaxOrNull ( declaredSymbol , ref id ) ;
653671 return SyntaxFactory . EventStatement (
654672 attributes ,
655673 CommonConversions . ConvertModifiers ( node . Modifiers , GetMemberContext ( node ) ) ,
656674 id ,
657675 null ,
658676 SyntaxFactory . SimpleAsClause ( returnAttributes ,
659677 ( TypeSyntax ) node . Declaration . Type . Accept ( TriviaConvertingVisitor ) ) ,
660- declaredSymbol == null ? null : CreateImplementsClauseSyntaxOrNull ( declaredSymbol , id ) ) ;
678+ implementsClauseSyntaxOrNull ) ;
661679 }
662680 private TypeSyntax GetTypeSyntax ( ITypeSymbol typeInfo ) {
663681 return ( TypeSyntax ) _vbSyntaxGenerator . TypeExpression ( typeInfo ) ;
0 commit comments