Skip to content

Commit c3a91c8

Browse files
Merge pull request #1124 from TymurGubayev/fix/StaticsWithSameNameInGetAndSet/1
Differentiate between statics in setters and getters
2 parents eb5d1c7 + 430d49b commit c3a91c8

7 files changed

Lines changed: 82 additions & 7 deletions

File tree

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,10 @@ public override async Task<CSharpSyntaxNode> VisitIdentifierName(VBasic.Syntax.I
15441544

15451545
var sym = GetSymbolInfoInDocument<ISymbol>(node);
15461546
if (sym is ILocalSymbol) {
1547+
if (sym.IsStatic && sym.ContainingSymbol is IMethodSymbol m && m.AssociatedSymbol is IPropertySymbol) {
1548+
qualifiedIdentifier = qualifiedIdentifier.WithParentPropertyAccessorKind(m.MethodKind);
1549+
}
1550+
15471551
var vbMethodBlock = node.Ancestors().OfType<VBasic.Syntax.MethodBlockBaseSyntax>().FirstOrDefault();
15481552
if (vbMethodBlock != null &&
15491553
vbMethodBlock.MustReturn() &&

CodeConverter/CSharp/HoistedFieldFromVbStaticVariable.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@ internal class HoistedFieldFromVbStaticVariable : IHoistedNode
66
{
77
public string OriginalMethodName { get; }
88
public string OriginalVariableName { get; }
9+
public MethodKind OriginalParentAccessorKind { get; }
910
public ExpressionSyntax Initializer { get; }
1011
public TypeSyntax Type { get; }
1112
public bool IsStatic { get; }
1213

13-
public HoistedFieldFromVbStaticVariable(string originalMethodName, string originalVariableName, ExpressionSyntax initializer, TypeSyntax type, bool isStatic)
14+
public HoistedFieldFromVbStaticVariable(string originalMethodName, string originalVariableName, MethodKind originalParentAccessorKind, ExpressionSyntax initializer, TypeSyntax type, bool isStatic)
1415
{
1516
OriginalMethodName = originalMethodName;
1617
OriginalVariableName = originalVariableName;
18+
OriginalParentAccessorKind = originalParentAccessorKind;
1719
Initializer = initializer;
1820
Type = type;
1921
IsStatic = isStatic;
2022
}
2123

2224
public string FieldName => OriginalMethodName != null ? $"_{OriginalMethodName}_{OriginalVariableName}" : $"_{OriginalVariableName}";
25+
public string PrefixedOriginalVariableName => PerScopeState.GetPrefixedName(OriginalParentAccessorKind == MethodKind.Ordinary ? "" : OriginalParentAccessorKind.ToString(), OriginalVariableName);
2326
}

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitLocalDeclarationSta
110110
string methodName;
111111
SyntaxTokenList methodModifiers;
112112

113+
MethodKind parentAccessorKind = MethodKind.Ordinary;
113114
if (_methodNode is VBSyntax.MethodBlockSyntax methodBlock) {
114115
var methodStatement = methodBlock.BlockStatement as VBSyntax.MethodStatementSyntax;
115116
methodModifiers = methodStatement.Modifiers;
@@ -120,13 +121,14 @@ public override async Task<SyntaxList<StatementSyntax>> VisitLocalDeclarationSta
120121
} else if (_methodNode is VBSyntax.AccessorBlockSyntax accessorBlock) {
121122
var propertyBlock = accessorBlock.Parent as VBSyntax.PropertyBlockSyntax;
122123
methodName = propertyBlock.PropertyStatement.Identifier.Text;
124+
parentAccessorKind = accessorBlock.IsKind(VBasic.SyntaxKind.GetAccessorBlock) ? MethodKind.PropertyGet : MethodKind.PropertySet;
123125
methodModifiers = propertyBlock.PropertyStatement.Modifiers;
124126
} else {
125127
throw new NotImplementedException(_methodNode.GetType() + " not implemented!");
126128
}
127129

128130
var isVbShared = methodModifiers.Any(a => a.IsKind(VBasic.SyntaxKind.SharedKeyword));
129-
_perScopeState.HoistToTopLevel(new HoistedFieldFromVbStaticVariable(methodName, variable.Identifier.Text, initializeValue, decl.Declaration.Type, isVbShared));
131+
_perScopeState.HoistToTopLevel(new HoistedFieldFromVbStaticVariable(methodName, variable.Identifier.Text, parentAccessorKind, initializeValue, decl.Declaration.Type, isVbShared));
130132
}
131133
} else {
132134
var shouldPullVariablesBeforeLoop = _perScopeState.IsInsideLoop() && declarator.Initializer is null && declarator.AsClause is not VBSyntax.AsNewClauseSyntax;

CodeConverter/CSharp/PerScopeState.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,22 @@ public async Task<SyntaxList<MemberDeclarationSyntax>> CreateVbStaticFieldsAsync
157157
var declarations = new List<FieldDeclarationSyntax>();
158158

159159
var fieldInfo = GetFields();
160-
var newNames = fieldInfo.ToDictionary(f => f.OriginalVariableName, f =>
160+
var newNames = fieldInfo.ToDictionary(f => f.PrefixedOriginalVariableName, f =>
161161
NameGenerator.CS.GetUniqueVariableNameInScope(semanticModel, generatedNames, typeNode, f.FieldName)
162162
);
163163
foreach (var field in fieldInfo) {
164164
var decl = (field.Initializer != null)
165-
? CommonConversions.CreateVariableDeclarationAndAssignment(newNames[field.OriginalVariableName], field.Initializer, field.Type)
166-
: SyntaxFactory.VariableDeclaration(field.Type, SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(newNames[field.OriginalVariableName])));
165+
? CommonConversions.CreateVariableDeclarationAndAssignment(newNames[field.PrefixedOriginalVariableName], field.Initializer, field.Type)
166+
: SyntaxFactory.VariableDeclaration(field.Type, SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(newNames[field.PrefixedOriginalVariableName])));
167167
var modifiers = new List<SyntaxToken> { CS.SyntaxFactory.Token(SyntaxKind.PrivateKeyword) };
168168
if (field.IsStatic || namedTypeSymbol.IsModuleType()) {
169169
modifiers.Add(CS.SyntaxFactory.Token(SyntaxKind.StaticKeyword));
170170
}
171-
declarations.Add(CS.SyntaxFactory.FieldDeclaration(CS.SyntaxFactory.List<AttributeListSyntax>(), CS.SyntaxFactory.TokenList(modifiers), decl));
171+
var fieldDecl = CS.SyntaxFactory.FieldDeclaration(CS.SyntaxFactory.List<AttributeListSyntax>(), CS.SyntaxFactory.TokenList(modifiers), decl);
172+
if (field.OriginalParentAccessorKind != MethodKind.Ordinary) {
173+
fieldDecl = fieldDecl.WithParentPropertyAccessorKind(field.OriginalParentAccessorKind);
174+
}
175+
declarations.Add(fieldDecl);
172176
}
173177

174178
var statementsWithUpdatedIds = ReplaceNames(declarations.Concat(csNodes), newNames);
@@ -185,11 +189,23 @@ public static IEnumerable<T> ReplaceNames<T>(IEnumerable<T> csNodes, Dictionary<
185189
public static T ReplaceNames<T>(T csNode, Dictionary<string, string> newNames) where T : SyntaxNode
186190
{
187191
return csNode.ReplaceNodes(csNode.DescendantNodesAndSelf().OfType<IdentifierNameSyntax>(), (_, idns) => {
188-
if (newNames.TryGetValue(idns.Identifier.ValueText, out var newName)) {
192+
if (TryGetValue(newNames, idns, out var newName)) {
189193
return idns.WithoutAnnotations(AdditionalLocalAnnotation).WithIdentifier(CS.SyntaxFactory.Identifier(newName));
190194
}
191195
return idns;
192196
});
197+
198+
static bool TryGetValue(Dictionary<string, string> newNames, IdentifierNameSyntax idns, out string newName)
199+
{
200+
var ann = idns.GetAnnotations(AnnotationConstants.ParentPropertyAccessorKindAnnotation).FirstOrDefault();
201+
var key = GetPrefixedName(ann?.Data, idns.Identifier.ValueText);
202+
return newNames.TryGetValue(key, out newName);
203+
}
204+
}
205+
206+
internal static string GetPrefixedName(string prefix, string name)
207+
{
208+
return string.IsNullOrEmpty(prefix) ? name : $"<{prefix}>.{name}";
193209
}
194210

195211
public IEnumerable<StatementSyntax> ConvertExit(VBasic.SyntaxKind vbBlockKeywordKind)

CodeConverter/Common/AnnotationConstants.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ internal static class AnnotationConstants
1212
public const string SourceEndLineAnnotationKind = "CodeConverter.SourceEndLine";
1313
public const string LeadingTriviaAlreadyMappedAnnotation = nameof(CodeConverter) + "." + nameof(LeadingTriviaAlreadyMappedAnnotation);
1414
public const string TrailingTriviaAlreadyMappedAnnotation = nameof(CodeConverter) + "." + nameof(TrailingTriviaAlreadyMappedAnnotation);
15+
public const string ParentPropertyAccessorKindAnnotation = nameof(CodeConverter) + "." + nameof(ParentPropertyAccessorKindAnnotation);
1516

1617
private static string AsString(LinePosition position)
1718
{
@@ -40,4 +41,9 @@ public static SyntaxAnnotation SourceEndLine(FileLinePositionSpan origLinespan)
4041
{
4142
return new SyntaxAnnotation(SourceEndLineAnnotationKind, origLinespan.EndLinePosition.Line.ToString(CultureInfo.InvariantCulture));
4243
}
44+
45+
public static SyntaxAnnotation ParentPropertyAccessorKind(string accessorKind)
46+
{
47+
return new SyntaxAnnotation(ParentPropertyAccessorKindAnnotation, accessorKind);
48+
}
4349
}

CodeConverter/Util/SyntaxNodeExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ private static T WithoutSourceMappingNonRecursive<T>(this T node) where T : Synt
173173
return node.WithoutAnnotations(AnnotationConstants.SourceStartLineAnnotationKind).WithoutAnnotations(AnnotationConstants.SourceEndLineAnnotationKind);
174174
}
175175

176+
public static T WithParentPropertyAccessorKind<T>(this T node, MethodKind accessorKind) where T : SyntaxNode
177+
{
178+
return node.WithAdditionalAnnotations(AnnotationConstants.ParentPropertyAccessorKind(accessorKind.ToString()));
179+
}
180+
176181
private static bool IsBlockParent(SyntaxNode converted, SyntaxToken lastCsConvertedToken)
177182
{
178183
return lastCsConvertedToken.Parent == converted || lastCsConvertedToken.Parent is BlockSyntax b && b.Parent == converted;

Tests/CSharp/MemberTests/MemberTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,45 @@ public void set_Prop(int i, string value)
665665
_Prop_bSet = false;
666666
}
667667
668+
}");
669+
}
670+
671+
[Fact]
672+
public async Task StaticLocalsInPropertyGetterAndSetterAsync()
673+
{
674+
await TestConversionVisualBasicToCSharpAsync(
675+
@"
676+
Public Property Prop As String
677+
Get
678+
Static b As Boolean
679+
b = True
680+
End Get
681+
682+
Set(ByVal s As String)
683+
Static b As Boolean
684+
b = False
685+
End Set
686+
End Property
687+
", @"
688+
internal partial class SurroundingClass
689+
{
690+
private bool _Prop_b;
691+
private bool _Prop_b1;
692+
693+
public string Prop
694+
{
695+
get
696+
{
697+
_Prop_b = true;
698+
return default;
699+
}
700+
701+
set
702+
{
703+
_Prop_b1 = false;
704+
}
705+
}
706+
668707
}");
669708
}
670709

0 commit comments

Comments
 (0)