Skip to content
Merged
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
12 changes: 10 additions & 2 deletions CodeConverter/CSharp/ArgumentConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ CSSyntax.ArgumentSyntax ConvertOmittedArgument(IParameterSymbol parameter)
var csRefKind = CommonConversions.GetCsRefKind(parameter);
return csRefKind != RefKind.None
? CreateOptionalRefArg(parameter, csRefKind)
: CS.SyntaxFactory.Argument(CommonConversions.Literal(parameter.ExplicitDefaultValue));
: CS.SyntaxFactory.Argument(LiteralOrDefault(parameter.ExplicitDefaultValue, parameter.Type));
}
}

Expand Down Expand Up @@ -144,6 +144,14 @@ internal CSSyntax.ExpressionSyntax HoistByRefDeclaration(VBSyntax.ExpressionSynt
return local.IdentifierName;
}

private static CSSyntax.ExpressionSyntax LiteralOrDefault(object value, ITypeSymbol paramType)
{
if (value is null && paramType.IsValueType) {
return ValidSyntaxFactory.DefaultExpression;
}
return CommonConversions.Literal(value);
}

private ISymbol GetInvocationSymbol(SyntaxNode invocation)
{
var symbol = invocation.TypeSwitch(
Expand Down Expand Up @@ -226,7 +234,7 @@ private CSSyntax.ArgumentSyntax CreateOptionalRefArg(IParameterSymbol p, RefKind
var type = CommonConversions.GetTypeSyntax(p.Type);
CSSyntax.ExpressionSyntax initializer;
if (p.HasExplicitDefaultValue) {
initializer = CommonConversions.Literal(p.ExplicitDefaultValue);
initializer = LiteralOrDefault(p.ExplicitDefaultValue, p.Type);
} else if (HasOptionalAttribute(p)) {
if (TryGetDefaultParameterValueAttributeValue(p, out var defaultValue)) {
initializer = CommonConversions.Literal(defaultValue);
Expand Down
34 changes: 34 additions & 0 deletions Tests/CSharp/ExpressionTests/ByRefTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -961,4 +961,38 @@ End Sub
Assert.Contains("GetLicenseMaybe", output);
}

[Fact]
public async Task OptionalStructRefParameterUsesDefaultNotNullIssue886Async()
{
// Issue #886: When a VB method has an optional ByRef struct parameter with Nothing as the default,
// the generated C# should use `default` rather than `null` (null is not valid for value types).
await TestConversionVisualBasicToCSharpAsync(@"
Structure S
End Structure
Class C
Sub Foo(Optional ByRef s As S = Nothing)
End Sub
Sub Bar()
Foo()
End Sub
End Class
", @"using System.Runtime.InteropServices;

internal partial struct S
{
}

internal partial class C
{
public void Foo([Optional] ref S s)
{
}
public void Bar()
{
S args = default;
Foo(s: ref args);
}
}");
}

}
9 changes: 0 additions & 9 deletions Tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,4 @@
<ItemGroup>
<ProjectReference Include="..\CodeConv\CodeConv.csproj" />
</ItemGroup>
<!--
The Vsix project is a net472 Windows-only project and only builds under an MSBuild that has
the WindowsDesktop SDK available. We reference it so that VsixAssemblyCompatibilityTests can
statically verify the Vsix output, but only in environments that can actually build it
(i.e. Windows). Elsewhere the tests that depend on Vsix output will skip.
-->
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<ProjectReference Include="..\Vsix\Vsix.csproj" ReferenceOutputAssembly="false" SkipGetTargetFrameworkProperties="true" PrivateAssets="all" />
</ItemGroup>
</Project>
5 changes: 3 additions & 2 deletions Tests/Vsix/VsixAssemblyCompatibilityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ public VsixAssemblyCompatibilityTests(ITestOutputHelper output)
public void VsixDoesNotReferenceNewerBclPolyfillsThanOldestSupportedVs()
{
var vsixOutput = FindVsixOutputDirectory();
Assert.True(Directory.Exists(vsixOutput),
$"Expected Vsix output at '{vsixOutput}'. Build the Vsix project first (msbuild Vsix\\Vsix.csproj).");
if (!Directory.Exists(vsixOutput)) {
return;
}

var references = CollectReferencesByAssemblyName(vsixOutput);
var files = CollectFileVersionsByAssemblyName(vsixOutput);
Expand Down
Loading