Skip to content

Commit 21da307

Browse files
Rename clashing type members - fixes #420
1 parent fe6e153 commit 21da307

11 files changed

Lines changed: 145 additions & 66 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1313
* Fix compilation error when switching with enum cases [#549](https://github.com/icsharpcode/CodeConverter/issues/549)
1414
* Improve numeric casts [#580](https://github.com/icsharpcode/CodeConverter/issues/580)
1515
* Add ref to conversion of RaiseEvent where needed [#584](https://github.com/icsharpcode/CodeConverter/issues/584)
16+
* Rename clashing type memvers [#420](https://github.com/icsharpcode/CodeConverter/issues/420)
1617

1718
### C# -> VB
1819

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using ICSharpCode.CodeConverter.Shared;
6+
using ICSharpCode.CodeConverter.Util;
7+
using ICSharpCode.CodeConverter.Util.FromRoslyn;
8+
using Microsoft.CodeAnalysis;
9+
10+
namespace ICSharpCode.CodeConverter.CSharp
11+
{
12+
internal static class ClashingMemberRenamer
13+
{
14+
/// <summary>
15+
/// Renames symbols in a VB project so that they don't clash with rules for C# member names, attempting to rename the least public ones first.
16+
/// See https://github.com/icsharpcode/CodeConverter/issues/420
17+
/// </summary>
18+
public static async Task<Project> RenameClashingSymbolsAsync(Project project)
19+
{
20+
var compilation = await project.GetCompilationAsync();
21+
var memberRenames = SymbolRenamer.GetNamespacesAndTypesInAssembly(project, compilation)
22+
.SelectMany(x => GetSymbolsWithNewNames(x, compilation));
23+
return await SymbolRenamer.PerformRenamesAsync(project, memberRenames.ToList());
24+
}
25+
26+
private static IEnumerable<(ISymbol Original, string NewName)> GetSymbolsWithNewNames(INamespaceOrTypeSymbol containerSymbol, Compilation compilation)
27+
{
28+
if (containerSymbol.IsNamespace) return Enumerable.Empty<(ISymbol Original, string NewName)>();
29+
30+
var members = containerSymbol.GetMembers()
31+
.Where(m => m.Locations.Any(loc => loc.SourceTree != null && compilation.ContainsSyntaxTree(loc.SourceTree)))
32+
.Where(s => containerSymbol.Name == s.Name || containerSymbol is INamedTypeSymbol nt && nt.IsEnumType() && SymbolRenamer.GetName(s).StartsWith(containerSymbol.Name));
33+
var symbolSet = containerSymbol.Yield().Concat(members).ToArray();
34+
return SymbolRenamer.GetSymbolsWithNewNames(symbolSet, new HashSet<string>(symbolSet.Select(SymbolRenamer.GetName)), true);
35+
}
36+
}
37+
}

CodeConverter/CSharp/VBToCSProjectContentsConverter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public VBToCSProjectContentsConverter(ConversionOptions conversionOptions, bool
4343

4444
public async Task InitializeSourceAsync(Project project)
4545
{
46+
project = await ClashingMemberRenamer.RenameClashingSymbolsAsync(project);
4647
var cSharpCompilationOptions = CSharpCompiler.CreateCompilationOptions();
4748
_convertedCsProject = project.ToProjectFromAnyOptions(cSharpCompilationOptions, CSharpCompiler.ParseOptions);
4849
_csharpReferenceProject = project.CreateReferenceOnlyProjectFromAnyOptions(cSharpCompilationOptions, CSharpCompiler.ParseOptions);

CodeConverter/Shared/SymbolRenamer.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal static class SymbolRenamer
1616
{
1717
var symbolsWithNewNames = toRename.OrderByDescending(x => x.DeclaredAccessibility).ThenByDescending(x => x.Kind == SymbolKind.Parameter || x.Kind == SymbolKind.Property).Skip(canKeepOne ? 1 :0).Select(tr =>
1818
{
19-
string newName = NameGenerator.GenerateUniqueName(GetBaseName(tr), canUse);
19+
string newName = NameGenerator.GenerateUniqueName(GetBaseForNewName(tr), canUse);
2020
return (Original: tr, NewName: newName);
2121
});
2222
return symbolsWithNewNames;
@@ -45,11 +45,16 @@ public static async Task<Project> PerformRenamesAsync(Project project, IReadOnly
4545
return solution.GetProject(project.Id);
4646
}
4747

48-
private static string GetBaseName(ISymbol declaration)
48+
private static string GetBaseForNewName(ISymbol declaration)
4949
{
50-
string prefix = declaration.Kind.ToString().ToLowerInvariant()[0] + "_";
5150
string name = GetName(declaration);
52-
return prefix + name.Substring(0, 1).ToUpperInvariant() + name.Substring(1);
51+
return declaration.Kind switch {
52+
SymbolKind.Method => name + "Method",
53+
SymbolKind.Property => name + "Prop",
54+
SymbolKind.NamedType => name + "Type",
55+
SymbolKind.Field => name + "Field",
56+
_ => declaration.Kind.ToString().ToLowerInvariant()[0] + name.Substring(0, 1).ToUpperInvariant() + name.Substring(1)
57+
};
5358
}
5459

5560
public static IEnumerable<INamespaceOrTypeSymbol> GetNamespacesAndTypesInAssembly(Project project, Compilation compilation)

Tests/CSharp/MemberTests/MemberTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,37 @@ public int FooDifferentName(ref string str, int i)
12431243
return 4;
12441244
}
12451245
}
1246+
");
1247+
}
1248+
1249+
[Fact]
1250+
public async Task Issue420_RenameClashingClassMemberAsync()
1251+
{
1252+
await TestConversionVisualBasicToCSharpAsync(
1253+
@"Module Main
1254+
Sub Main()
1255+
End Sub
1256+
End Module", @"
1257+
internal static partial class MainType
1258+
{
1259+
public static void Main()
1260+
{
1261+
}
1262+
}
1263+
");
1264+
}
1265+
1266+
[Fact]
1267+
public async Task Issue420_RenameClashingEnumMemberAsync()
1268+
{
1269+
await TestConversionVisualBasicToCSharpAsync(
1270+
@"Enum MyEnum
1271+
MyEnumFirst
1272+
End Enum", @"
1273+
internal enum MyEnumType
1274+
{
1275+
MyEnumFirst
1276+
}
12461277
");
12471278
}
12481279
}

Tests/TestData/MultiFileCharacterization/VBToCSResults/ConvertVbLibraryOnly/VbLibrary/AClass.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ private void UseOutParameterInClass()
2828
dict.TryGetValue(1, out argvalue);
2929
}
3030

31-
private void UseEnumFromOtherFileInSolution(AnEnum m)
31+
private void UseEnumFromOtherFileInSolution(AnEnumType m)
3232
{
33-
string nothing = Enumerable.Empty<string>().ToArray()[(int)AnEnum.AnEnumMember];
33+
string nothing = Enumerable.Empty<string>().ToArray()[(int)AnEnumType.AnEnumMember];
3434
switch (m)
3535
{
36-
case (AnEnum)(-1):
36+
case (AnEnumType)(-1):
3737
{
3838
return;
3939
}
4040

41-
case AnEnum.AnEnumMember:
41+
case AnEnumType.AnEnumMember:
4242
{
4343
return;
4444
}

Tests/TestData/MultiFileCharacterization/VBToCSResults/ConvertVbLibraryOnly/VbLibrary/AnEnum.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
namespace VbLibrary
33
{
4-
internal enum AnEnum
4+
internal enum AnEnumType
55
{
66
AnEnumMember
77
}

Tests/TestData/MultiFileCharacterization/VBToCSResults/ConvertWholeSolution/VbLibrary/AClass.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ private void UseOutParameterInClass()
2828
dict.TryGetValue(1, out argvalue);
2929
}
3030

31-
private void UseEnumFromOtherFileInSolution(AnEnum m)
31+
private void UseEnumFromOtherFileInSolution(AnEnumType m)
3232
{
33-
string nothing = Enumerable.Empty<string>().ToArray()[(int)AnEnum.AnEnumMember];
33+
string nothing = Enumerable.Empty<string>().ToArray()[(int)AnEnumType.AnEnumMember];
3434
switch (m)
3535
{
36-
case (AnEnum)(-1):
36+
case (AnEnumType)(-1):
3737
{
3838
return;
3939
}
4040

41-
case AnEnum.AnEnumMember:
41+
case AnEnumType.AnEnumMember:
4242
{
4343
return;
4444
}

Tests/TestData/MultiFileCharacterization/VBToCSResults/ConvertWholeSolution/VbLibrary/AnEnum.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
namespace VbLibrary
33
{
4-
internal enum AnEnum
4+
internal enum AnEnumType
55
{
66
AnEnumMember
77
}

Tests/VB/MemberTests.cs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -554,14 +554,14 @@ public int Test1 {
554554
}
555555
",
556556
@"Public Class HasConflictingPropertyAndField
557-
Private f_Test As Integer
557+
Private testField As Integer
558558
559559
Public Property Test As Integer
560560
Get
561-
Return f_Test
561+
Return testField
562562
End Get
563563
Set(ByVal value As Integer)
564-
f_Test = value
564+
testField = value
565565
End Set
566566
End Property
567567
End Class
@@ -610,26 +610,26 @@ public int Test(int arg) {
610610
}",
611611
@"Public Class HasConflictingMethodAndField
612612
Public Function HasConflictingParam(ByVal test As Integer) As Integer
613-
f_TeSt = test
613+
teStField = test
614614
Return test
615615
End Function
616616
617-
Private f_TeSt As Integer
617+
Private teStField As Integer
618618
619-
Private Function m_Test() As Integer
619+
Private Function testMethod() As Integer
620620
Return 1
621621
End Function
622622
623623
Public Function Test() As Integer
624-
Return m_Test()
624+
Return testMethod()
625625
End Function
626626
627-
Private Function m_Test(ByVal arg As Integer) As Integer
627+
Private Function testMethod(ByVal arg As Integer) As Integer
628628
Return arg
629629
End Function
630630
631631
Public Function Test(ByVal arg As Integer) As Integer
632-
Return m_Test(arg)
632+
Return testMethod(arg)
633633
End Function
634634
End Class");
635635
}
@@ -653,18 +653,18 @@ public int Test {
653653
}",
654654
@"Public Class HasConflictingPropertyAndField
655655
Public Function HasConflictingParam(ByVal test As Integer) As Integer
656-
f_Test = test
656+
testField = test
657657
Return test
658658
End Function
659659
660-
Private f_Test As Integer
660+
Private testField As Integer
661661
662662
Public Property Test As Integer
663663
Get
664-
Return f_Test
664+
Return testField
665665
End Get
666666
Set(ByVal value As Integer)
667-
f_Test = value
667+
testField = value
668668
End Set
669669
End Property
670670
End Class");
@@ -685,14 +685,14 @@ public int HasConflictingParam(int test) {
685685
}
686686
}",
687687
@"Public Class HasConflictingPropertyAndField
688-
Private f_Test As Integer
688+
Private testField As Integer
689689
690690
Public Property Test As Integer
691691
Get
692-
Return f_Test
692+
Return testField
693693
End Get
694694
Set(ByVal value As Integer)
695-
f_Test = value
695+
testField = value
696696
End Set
697697
End Property
698698
@@ -727,22 +727,22 @@ public int Test {
727727
}",
728728
@"Public Partial Class HasConflictingPropertyAndField
729729
Public Function HasConflictingParam(ByVal test As Integer) As Integer
730-
Dim l_TEST As Integer = 0
731-
f_Test = test + l_TEST
730+
Dim lTEST As Integer = 0
731+
testField = test + lTEST
732732
Return test
733733
End Function
734734
End Class
735735
736736
Public Partial Class HasConflictingPropertyAndField
737-
Private f_Test As Integer
737+
Private testField As Integer
738738
739739
Public Property Test As Integer
740740
Get
741-
Dim l_TEST As Integer = 0
742-
Return f_Test + l_TEST
741+
Dim lTEST As Integer = 0
742+
Return testField + lTEST
743743
End Get
744744
Set(ByVal value As Integer)
745-
f_Test = value
745+
testField = value
746746
End Set
747747
End Property
748748
End Class");
@@ -1122,15 +1122,15 @@ class OwnerClass : INotifyPropertyChanged {
11221122
@"Imports System.ComponentModel
11231123
11241124
Friend Class TestClass
1125-
Private f_Owner As OwnerClass
1125+
Private ownerField As OwnerClass
11261126
11271127
Public Property Owner As OwnerClass
11281128
Get
1129-
Return f_Owner
1129+
Return ownerField
11301130
End Get
11311131
Set(ByVal value As OwnerClass)
1132-
f_Owner = value
1133-
AddHandler CType(f_Owner, INotifyPropertyChanged).PropertyChanged, AddressOf OnOwnerChanged
1132+
ownerField = value
1133+
AddHandler CType(ownerField, INotifyPropertyChanged).PropertyChanged, AddressOf OnOwnerChanged
11341134
End Set
11351135
End Property
11361136

0 commit comments

Comments
 (0)