Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CodeConverter/CSharp/CommonConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ public SyntaxToken ConvertIdentifier(SyntaxToken id, bool isAttribute = false, S
text = "value";
} else if (normalizedText.StartsWith("_", StringComparison.OrdinalIgnoreCase) && idSymbol is IFieldSymbol propertyFieldSymbol && propertyFieldSymbol.AssociatedSymbol?.IsKind(SymbolKind.Property) == true) {
text = propertyFieldSymbol.AssociatedSymbol.Name;
if (propertyFieldSymbol.AssociatedSymbol.IsVirtual && !propertyFieldSymbol.AssociatedSymbol.IsAbstract) {
text = "MyClass" + text;
}
} else if (normalizedText.EndsWith("Event", StringComparison.OrdinalIgnoreCase) && idSymbol is IFieldSymbol eventFieldSymbol && eventFieldSymbol.AssociatedSymbol?.IsKind(SymbolKind.Event) == true) {
text = eventFieldSymbol.AssociatedSymbol.Name;
} else if (WinformsConversions.MayNeedToInlinePropertyAccess(id.Parent, idSymbol) && _typeContext.HandledEventsAnalysis.ShouldGeneratePropertyFor(idSymbol.Name)) {
Expand Down
15 changes: 13 additions & 2 deletions CodeConverter/CSharp/DeclarationNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ var dummyClass

public override async Task<CSharpSyntaxNode> VisitClassBlock(VBSyntax.ClassBlockSyntax node)
{
_accessorDeclarationNodeConverter.AccessedThroughMyClass = GetMyClassAccessedNames(node);
_accessorDeclarationNodeConverter.AccessedThroughMyClass = GetMyClassAccessedNames(node, _semanticModel);
var classStatement = node.ClassStatement;
var attributes = await CommonConversions.ConvertAttributesAsync(classStatement.AttributeLists);
var (parameters, constraints) = await SplitTypeParametersAsync(classStatement.TypeParameterList);
Expand Down Expand Up @@ -689,12 +689,23 @@ private static async Task<BlockSyntax> ConvertStatementsAsync(SyntaxList<VBSynta
return CS.SyntaxFactory.Block(await statements.SelectManyAsync(async s => (IEnumerable<StatementSyntax>) await s.Accept(methodBodyVisitor)));
}

private static HashSet<string> GetMyClassAccessedNames(VBSyntax.ClassBlockSyntax classBlock)
private static HashSet<string> GetMyClassAccessedNames(VBSyntax.ClassBlockSyntax classBlock, SemanticModel semanticModel)
{
var memberAccesses = classBlock.DescendantNodes().OfType<VBSyntax.MemberAccessExpressionSyntax>();
var accessedTextNames = new HashSet<string>(memberAccesses
.Where(mae => mae.Expression is VBSyntax.MyClassExpressionSyntax)
.Select(mae => mae.Name.Identifier.Text), StringComparer.OrdinalIgnoreCase);

var identifierNames = classBlock.DescendantNodes().OfType<VBSyntax.IdentifierNameSyntax>().Where(id => id.Identifier.Text.StartsWith("_", StringComparison.OrdinalIgnoreCase));
foreach (var id in identifierNames)
{
var symbolInfo = semanticModel.GetSymbolInfo(id);
if (symbolInfo.Symbol is IFieldSymbol fieldSymbol && fieldSymbol.AssociatedSymbol != null && fieldSymbol.AssociatedSymbol.IsVirtual && !fieldSymbol.AssociatedSymbol.IsAbstract)
{
accessedTextNames.Add(fieldSymbol.AssociatedSymbol.Name);
}
}

return accessedTextNames;
}

Expand Down
47 changes: 46 additions & 1 deletion Tests/VB/MemberTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1495,4 +1495,49 @@ End Sub
End Class");
}

}

[Fact]
public async Task TestMyClassPropertyAccess()
{
await TestConversionVisualBasicToCSharpAsync(@"
Class Foo
Overridable Property Prop As Integer = 5

Sub Test()
_Prop = 10 ' This should convert to MyClassProp = 10 not to Prop = 10
Dim isCorrect = MyClass.Prop = 10 ' After conversion this will return 5instead of 10 because we wrote to Child.Prop
End Sub
End Class
Class Child
Inherits Foo
Overrides Property Prop As Integer = 20
End Class", @"
internal partial class Foo
{
public int MyClassProp { get; set; } = 5;

public virtual int Prop
{
get
{
return MyClassProp;
}

set
{
MyClassProp = value;
}
}

public void Test()
{
MyClassProp = 10; // This should convert to MyClassProp = 10 not to Prop = 10
bool isCorrect = MyClassProp == 10; // After conversion this will return 5instead of 10 because we wrote to Child.Prop
}
}
internal partial class Child : Foo
{
public override int Prop { get; set; } = 20;
}");
}
}
Loading