Skip to content

Commit

Permalink
Cast to dynamic when the accessed member can't be found but the surro…
Browse files Browse the repository at this point in the history
…unding object can - fixes #786

There's probably a more specific condition which should trigger this if we look in Roslyn code
  • Loading branch information
GrahamTheCoder committed Dec 18, 2023
1 parent bc6b62a commit 60bee52
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
6 changes: 6 additions & 0 deletions CodeConverter/CSharp/ExpressionNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,12 @@ public override async Task<CSharpSyntaxNode> VisitMemberAccessExpression(VBasic.
}
if (left == null) {
left = await node.Expression.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
if (left != null && _semanticModel.GetSymbolInfo(node) is {CandidateReason: CandidateReason.LateBound, CandidateSymbols.Length: 0}
&& _semanticModel.GetSymbolInfo(node.Expression).Symbol is {Kind: var expressionSymbolKind}
&& expressionSymbolKind != SymbolKind.ErrorType
&& _semanticModel.GetOperation(node) is IDynamicMemberReferenceOperation) {
left = SyntaxFactory.ParenthesizedExpression(SyntaxFactory.CastExpression(SyntaxFactory.ParseTypeName("dynamic"), left));
}
}
if (left == null) {
if (IsSubPartOfConditionalAccess(node)) {
Expand Down
37 changes: 37 additions & 0 deletions Tests/CSharp/ExpressionTests/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,43 @@ private void TestMethod(string a)
}");
}

[Fact]
public async Task DynamicTestAsync()
{
await TestConversionVisualBasicToCSharpAsync(@"
Public Class C
Public Function IsPointWithinBoundaryBox(ByVal dblLat As Double, dblLon As Double, ByVal boundbox As Object) As Boolean
If boundbox IsNot Nothing Then
Dim boolInLatBounds As Boolean = (dblLat <= boundbox.north) And (dblLat >= boundbox.south) 'Less then highest (northmost) lat, AND more than lowest (southmost) lat
Dim boolInLonBounds As Boolean = (dblLon >= boundbox.west) And (dblLon <= boundbox.east) 'More than lowest (westmost) lat, AND less than highest (eastmost) lon
Return boolInLatBounds And boolInLonBounds
Else
'Throw New Exception(""boundbox is null."")
End If
Return False
End Function
End Class
", @"using Microsoft.VisualBasic.CompilerServices; // Install-Package Microsoft.VisualBasic
public partial class C
{
public bool IsPointWithinBoundaryBox(double dblLat, double dblLon, object boundbox)
{
if (boundbox is not null)
{
bool boolInLatBounds = Conversions.ToBoolean(Operators.AndObject(Operators.ConditionalCompareObjectLessEqual(dblLat, ((dynamic)boundbox).north, false), Operators.ConditionalCompareObjectGreaterEqual(dblLat, ((dynamic)boundbox).south, false))); // Less then highest (northmost) lat, AND more than lowest (southmost) lat
bool boolInLonBounds = Conversions.ToBoolean(Operators.AndObject(Operators.ConditionalCompareObjectGreaterEqual(dblLon, ((dynamic)boundbox).west, false), Operators.ConditionalCompareObjectLessEqual(dblLon, ((dynamic)boundbox).east, false))); // More than lowest (westmost) lat, AND less than highest (eastmost) lon
return boolInLatBounds & boolInLonBounds;
}
else
{
// Throw New Exception(""boundbox is null."")
}
return false;
}
}");
}

[Fact]
public async Task ConversionOfNotUsesParensIfNeededAsync()
{
Expand Down
9 changes: 4 additions & 5 deletions Tests/CSharp/StandaloneStatementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,12 @@ End If
var cmccIds = new List<int>();
foreach (var scr in _sponsorPayment.SponsorClaimRevisions)
{
foreach (var claim in (IEnumerable)scr.Claims)
foreach (var claim in (IEnumerable)((dynamic)scr).Claims)
{
if (claim.ClaimSummary is ClaimSummary)
if (((dynamic)claim).ClaimSummary is ClaimSummary)
{
{
var withBlock = (ClaimSummary)claim.ClaimSummary;
var withBlock = (ClaimSummary)((dynamic)claim).ClaimSummary;
cmccIds.AddRange(withBlock.UnpaidClaimMealCountCalculationsIds);
}
}
Expand All @@ -151,9 +151,8 @@ End If
2 source compilation errors:
BC30451: '_sponsorPayment' is not declared. It may be inaccessible due to its protection level.
BC30002: Type 'ClaimSummary' is not defined.
3 target compilation errors:
2 target compilation errors:
CS0103: The name '_sponsorPayment' does not exist in the current context
CS1061: 'object' does not contain a definition for 'ClaimSummary' and no accessible extension method 'ClaimSummary' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
CS0246: The type or namespace name 'ClaimSummary' could not be found (are you missing a using directive or an assembly reference?)");
}
}

0 comments on commit 60bee52

Please sign in to comment.