Skip to content

Commit 512ef7c

Browse files
Include type info in conversion of default(someType) - fixes #486
1 parent bdcc7b6 commit 512ef7c

10 files changed

Lines changed: 68 additions & 16 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1818

1919
### C# -> VB
2020
* Rename explicit method implementations where needed [#492](https://github.com/icsharpcode/CodeConverter/issues/492)
21+
* Include type information in conversion of default(someType) [#486](https://github.com/icsharpcode/CodeConverter/issues/486)
2122

2223
## [8.1.4] - 2020-06-26
2324

CodeConverter/CSharp/CommonConversions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ private async Task<ExpressionSyntax> IncreaseArrayUpperBoundExpressionAsync(VBSy
492492

493493
if (op is IBinaryOperation bOp && bOp.OperatorKind == BinaryOperatorKind.Subtract &&
494494
bOp.RightOperand.ConstantValue.HasValue && bOp.RightOperand.ConstantValue.Value is int subtractedVal && subtractedVal == 1
495-
&& convertedExpression.SkipParens() is CSSyntax.BinaryExpressionSyntax bExp && bExp.IsKind(CSSyntaxKind.SubtractExpression))
495+
&& convertedExpression.SkipIntoParens() is CSSyntax.BinaryExpressionSyntax bExp && bExp.IsKind(CSSyntaxKind.SubtractExpression))
496496
return bExp.Left;
497497

498498
return SyntaxFactory.BinaryExpression(

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ public override async Task<CSharpSyntaxNode> VisitSimpleArgument(VBasic.Syntax.S
407407
return await node.Expression.AcceptAsync(TriviaConvertingExpressionVisitor);
408408
var symbol = GetInvocationSymbol(invocation);
409409
SyntaxToken token = default(SyntaxToken);
410-
var convertedArgExpression = ((ExpressionSyntax)await node.Expression.AcceptAsync(TriviaConvertingExpressionVisitor)).SkipParens();
410+
var convertedArgExpression = ((ExpressionSyntax)await node.Expression.AcceptAsync(TriviaConvertingExpressionVisitor)).SkipIntoParens();
411411
var typeConversionAnalyzer = CommonConversions.TypeConversionAnalyzer;
412412
var possibleParameters = (CommonConversions.GetCsOriginalSymbolOrNull(symbol?.OriginalDefinition) ?? symbol)?.GetParameters();
413413
if (possibleParameters.HasValue) {
@@ -679,7 +679,7 @@ private ExpressionSyntax AsBool(VBSyntax.UnaryExpressionSyntax node, ExpressionS
679679

680680
private async Task<ExpressionSyntax> NegateAndSimplifyOrNullAsync(VBSyntax.UnaryExpressionSyntax node, ExpressionSyntax expr)
681681
{
682-
if (await _operatorConverter.ConvertNothingComparisonOrNullAsync(node.Operand.SkipParens(), true) is ExpressionSyntax nothingComparison) {
682+
if (await _operatorConverter.ConvertNothingComparisonOrNullAsync(node.Operand.SkipIntoParens(), true) is ExpressionSyntax nothingComparison) {
683683
return nothingComparison;
684684
} else if (expr is BinaryExpressionSyntax bes && bes.OperatorToken.IsKind(SyntaxKind.EqualsToken)) {
685685
return bes.WithOperatorToken(SyntaxFactory.Token(SyntaxKind.ExclamationEqualsToken));
@@ -914,7 +914,7 @@ bool RequiresLocalFunction(VBSyntax.InvocationExpressionSyntax invocation, IMeth
914914
var refConversion = GetRefConversionType(a, invocation.ArgumentList, invocationSymbol.Parameters, out var argName, out var refKind);
915915
if (RefConversion.Inline == refConversion) return false;
916916
if (!(a is VBSyntax.SimpleArgumentSyntax sas)) return false;
917-
var argExpression = sas.Expression.SkipParens();
917+
var argExpression = sas.Expression.SkipIntoParens();
918918
if (argExpression is VBSyntax.InstanceExpressionSyntax) return false;
919919
return !_semanticModel.GetConstantValue(argExpression).HasValue;
920920
}
@@ -992,7 +992,7 @@ public override async Task<CSharpSyntaxNode> VisitParameter(VBSyntax.ParameterSy
992992

993993
EqualsValueClauseSyntax @default = null;
994994
if (node.Default != null) {
995-
var defaultValue = node.Default.Value.SkipParens();
995+
var defaultValue = node.Default.Value.SkipIntoParens();
996996
if (_semanticModel.GetTypeInfo(defaultValue).Type?.SpecialType == SpecialType.System_DateTime) {
997997
var constant = _semanticModel.GetConstantValue(defaultValue);
998998
if (constant.HasValue && constant.Value is DateTime dt) {
@@ -1354,7 +1354,7 @@ private RefConversion NeedsVariableForArgument(VBasic.Syntax.ArgumentSyntax node
13541354
{
13551355
if (refKind == RefKind.None) return RefConversion.Inline;
13561356
if (!(node is VBSyntax.SimpleArgumentSyntax sas)) return RefConversion.PreAssigment;
1357-
var expression = sas.Expression.SkipParens();
1357+
var expression = sas.Expression.SkipIntoParens();
13581358

13591359
return GetRefConversion(expression);
13601360

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,8 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
561561
var csStepValue = (ExpressionSyntax)await (stmt.StepClause?.StepValue).AcceptAsync(_expressionVisitor);
562562
// For an enum, you need to add on an integer for example:
563563
var forceStepType = controlVarType is INamedTypeSymbol nt && nt.IsEnumType() ? nt.EnumUnderlyingType : controlVarType;
564-
csStepValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(vbStepValue, csStepValue?.SkipParens(), forceTargetType: forceStepType);
565-
csToValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(stmt.ToValue, csToValue?.SkipParens(), forceTargetType: controlVarType);
564+
csStepValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(vbStepValue, csStepValue?.SkipIntoParens(), forceTargetType: forceStepType);
565+
csToValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(stmt.ToValue, csToValue?.SkipIntoParens(), forceTargetType: controlVarType);
566566

567567
var nonNegativeCondition = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, id, csToValue);
568568
var negativeCondition = SyntaxFactory.BinaryExpression(SyntaxKind.GreaterThanOrEqualExpression, id, csToValue);
@@ -741,7 +741,7 @@ private static CasePatternSwitchLabelSyntax VarWhen(SyntaxToken varName, Express
741741

742742
private async Task<bool> CanEvaluateMultipleTimesAsync(VBSyntax.ExpressionSyntax vbExpr)
743743
{
744-
return _semanticModel.GetConstantValue(vbExpr).HasValue || vbExpr.SkipParens() is VBSyntax.NameSyntax ns && await IsNeverMutatedAsync(ns);
744+
return _semanticModel.GetConstantValue(vbExpr).HasValue || vbExpr.SkipIntoParens() is VBSyntax.NameSyntax ns && await IsNeverMutatedAsync(ns);
745745
}
746746

747747
private async Task<bool> IsNeverMutatedAsync(VBSyntax.NameSyntax ns)

CodeConverter/CSharp/TypeConversionAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ public static bool ConvertStringToCharLiteral(Microsoft.CodeAnalysis.VisualBasic
326326
var preferChar = node.Parent is VBSyntax.PredefinedCastExpressionSyntax pces &&
327327
pces.Keyword.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.CCharKeyword)
328328
|| convertedType?.SpecialType == SpecialType.System_Char;
329-
if (preferChar && node.SkipParens() is VBSyntax.LiteralExpressionSyntax les &&
329+
if (preferChar && node.SkipIntoParens() is VBSyntax.LiteralExpressionSyntax les &&
330330
les.Token.Value is string str &&
331331
str.Length == 1) {
332332
chr = str.Single();

CodeConverter/CSharp/VisualBasicEqualityComparison.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public RequiredType GetObjectEqualityType(params TypeInfo[] typeInfos)
8686

8787
private static bool IsNonEmptyStringLiteral(VBSyntax.ExpressionSyntax vbExpr)
8888
{
89-
return vbExpr.SkipParens().IsKind(VBSyntaxKind.StringLiteralExpression) && vbExpr is VBSyntax.LiteralExpressionSyntax literal && !IsEmptyString(literal);
89+
return vbExpr.SkipIntoParens().IsKind(VBSyntaxKind.StringLiteralExpression) && vbExpr is VBSyntax.LiteralExpressionSyntax literal && !IsEmptyString(literal);
9090
}
9191

9292
public ExpressionSyntax VbCoerceToNonNullString(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeInfo typeInfo, bool knownNotNull = false)

CodeConverter/Util/CSharpUtil.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ private static ExpressionSyntax InvertConditionInternal(ExpressionSyntax conditi
2929
var uOp = (PrefixUnaryExpressionSyntax)condition;
3030
if (uOp.IsKind(SyntaxKind.LogicalNotExpression)) {
3131
if (!(uOp.Parent is ExpressionSyntax))
32-
return uOp.Operand.SkipParens();
32+
return uOp.Operand.SkipIntoParens();
3333
return uOp.Operand;
3434
}
3535
return SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, uOp);

CodeConverter/Util/SyntaxExtensions.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ private static IEnumerable<SyntaxToken> GetSkippedTokens(SyntaxTriviaList list)
2020
.SelectMany(t => ((VBSyntax.SkippedTokensTriviaSyntax)t.GetStructure()).Tokens);
2121
}
2222

23-
public static CS.Syntax.ExpressionSyntax SkipParens(this CS.Syntax.ExpressionSyntax expression)
23+
public static CS.Syntax.ExpressionSyntax SkipIntoParens(this CS.Syntax.ExpressionSyntax expression)
2424
{
2525
if (expression == null)
2626
return null;
@@ -30,7 +30,7 @@ public static CS.Syntax.ExpressionSyntax SkipParens(this CS.Syntax.ExpressionSyn
3030
return expression;
3131
}
3232

33-
public static VBSyntax.ExpressionSyntax SkipParens(this VBSyntax.ExpressionSyntax expression)
33+
public static VBSyntax.ExpressionSyntax SkipIntoParens(this VBSyntax.ExpressionSyntax expression)
3434
{
3535
if (expression == null)
3636
return null;
@@ -40,6 +40,26 @@ public static VBSyntax.ExpressionSyntax SkipParens(this VBSyntax.ExpressionSynta
4040
return expression;
4141
}
4242

43+
public static CS.Syntax.ExpressionSyntax SkipOutOfParens(this CS.Syntax.ExpressionSyntax expression)
44+
{
45+
if (expression == null)
46+
return null;
47+
while (expression is CS.Syntax.ParenthesizedExpressionSyntax pes) {
48+
expression = pes.Parent as CS.Syntax.ExpressionSyntax;
49+
}
50+
return expression;
51+
}
52+
53+
public static VBSyntax.ExpressionSyntax SkipOutOfParens(this VBSyntax.ExpressionSyntax expression)
54+
{
55+
if (expression == null)
56+
return null;
57+
while (expression is VBSyntax.ParenthesizedExpressionSyntax pes) {
58+
expression = pes.Parent as VBSyntax.ExpressionSyntax;
59+
}
60+
return expression;
61+
}
62+
4363
public static bool IsParentKind(this SyntaxNode node, CS.SyntaxKind kind)
4464
{
4565
return node != null && node.Parent.IsKind(kind);

CodeConverter/VB/NodesVisitor.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,8 @@ public override VisualBasicSyntaxNode VisitLiteralExpression(CSS.LiteralExpressi
840840
{
841841
if (node.IsKind(CS.SyntaxKind.DefaultLiteralExpression)) {
842842
return VisualBasicSyntaxFactory.NothingExpression;
843+
} else if (node.IsKind(CS.SyntaxKind.NullLiteralExpression)) {
844+
return CreateTypedNothing(node);
843845
} else if (node.IsKind(CS.SyntaxKind.StringLiteralExpression) && CS.CSharpExtensions.IsVerbatimStringLiteral(node.Token)) {
844846
return SyntaxFactory.StringLiteralExpression(
845847
SyntaxFactory.StringLiteralToken(
@@ -1186,7 +1188,15 @@ public override VisualBasicSyntaxNode VisitMemberBindingExpression(CSS.MemberBin
11861188

11871189
public override VisualBasicSyntaxNode VisitDefaultExpression(CSS.DefaultExpressionSyntax node)
11881190
{
1189-
return SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword));
1191+
return CreateTypedNothing(node);
1192+
}
1193+
1194+
private VisualBasicSyntaxNode CreateTypedNothing(CSS.ExpressionSyntax node)
1195+
{
1196+
var nothing = VisualBasicSyntaxFactory.NothingExpression;
1197+
return _semanticModel.GetTypeInfo(node).ConvertedType is ITypeSymbol t
1198+
? (VisualBasicSyntaxNode) _commonConversions.VbSyntaxGenerator.CastExpression(t, nothing)
1199+
: nothing;
11901200
}
11911201

11921202
public override VisualBasicSyntaxNode VisitThisExpression(CSS.ThisExpressionSyntax node)
@@ -1558,7 +1568,7 @@ public override VisualBasicSyntaxNode VisitThrowExpression(CSS.ThrowExpressionSy
15581568

15591569
public override VisualBasicSyntaxNode VisitCasePatternSwitchLabel(CSS.CasePatternSwitchLabelSyntax node)
15601570
{
1561-
var condition = node.WhenClause.Condition.SkipParens();
1571+
var condition = node.WhenClause.Condition.SkipIntoParens();
15621572
switch (condition) {
15631573
case CSS.BinaryExpressionSyntax bes when node.Pattern.ToString().StartsWith("var"): //VarPatternSyntax (not available in current library version)
15641574
var basicSyntaxNode = (ExpressionSyntax)bes.Right.Accept(TriviaConvertingVisitor);

Tests/VB/ExpressionTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ Public Sub New()
966966
End Sub
967967
End Class");
968968
}
969+
969970
[Fact]
970971
public async Task PrefixUnaryExpression_SingleLineFunctionAsync() {
971972
await TestConversionCSharpToVisualBasicAsync(
@@ -980,6 +981,26 @@ Dim func As Func(Of String, Boolean) = Function(o) Not String.IsNullOrEmpty(""te
980981
End Sub
981982
End Class");
982983
}
984+
985+
[Fact]
986+
public async Task Issue486_MustCastNothingAsync() {
987+
await TestConversionCSharpToVisualBasicAsync(
988+
@"public class WhyWeNeedToCastNothing
989+
{
990+
public void Example(int? vbInitValue)
991+
{
992+
var withDefault = vbInitValue != null ? 7 : default(int?);
993+
var withNull = vbInitValue != null ? (int?)8 : null;
994+
}
995+
}",
996+
@"Public Class WhyWeNeedToCastNothing
997+
Public Sub Example(ByVal vbInitValue As Integer?)
998+
Dim withDefault = If(vbInitValue IsNot Nothing, 7, DirectCast(Nothing, Integer?))
999+
Dim withNull = If(vbInitValue IsNot Nothing, 8, DirectCast(Nothing, Integer?))
1000+
End Sub
1001+
End Class");
1002+
}
1003+
9831004
[Fact]
9841005
public async Task EqualsExpressionAsync() {
9851006
await TestConversionCSharpToVisualBasicAsync(

0 commit comments

Comments
 (0)