Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

take parameter attributes into account in CreateOptionalRefArg #1122

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
48 changes: 47 additions & 1 deletion CodeConverter/CSharp/ExpressionNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1818,8 +1818,54 @@ private ArgumentSyntax CreateExtraArgOrNull(IParameterSymbol p, bool requiresCom
private ArgumentSyntax CreateOptionalRefArg(IParameterSymbol p, RefKind refKind)
{
string prefix = $"arg{p.Name}";
var local = _typeContext.PerScopeState.Hoist(new AdditionalDeclaration(prefix, CommonConversions.Literal(p.ExplicitDefaultValue), CommonConversions.GetTypeSyntax(p.Type)));
var type = CommonConversions.GetTypeSyntax(p.Type);
ExpressionSyntax initializer;
if (p.HasExplicitDefaultValue) {
initializer = CommonConversions.Literal(p.ExplicitDefaultValue);
} else if (HasOptionalAttribute(p)) {
if (TryGetDefaultParameterValueAttributeValue(p, out var defaultValue)){
initializer = CommonConversions.Literal(defaultValue);
} else {
initializer = SyntaxFactory.DefaultExpression(type);
}
} else {
//invalid VB.NET code
return null;
}
var local = _typeContext.PerScopeState.Hoist(new AdditionalDeclaration(prefix, initializer, type));
return (ArgumentSyntax)CommonConversions.CsSyntaxGenerator.Argument(p.Name, refKind, local.IdentifierName);

bool HasOptionalAttribute(IParameterSymbol p)
{
var optionalAttribute = _semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.OptionalAttribute");
if (optionalAttribute == null) {
return false;
}

return p.GetAttributes().Any(a => SymbolEqualityComparer.IncludeNullability.Equals(a.AttributeClass, optionalAttribute));
}

bool TryGetDefaultParameterValueAttributeValue(IParameterSymbol p, out object defaultValue)
{
defaultValue = null;

var defaultParameterValueAttribute = _semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.InteropServices.DefaultParameterValueAttribute");
TymurGubayev marked this conversation as resolved.
Show resolved Hide resolved
if (defaultParameterValueAttribute == null) {
return false;
}

var attributeData = p.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.IncludeNullability.Equals(a.AttributeClass, defaultParameterValueAttribute));
if (attributeData == null) {
return false;
}

if (attributeData.ConstructorArguments.Length == 0) {
return false;
}

defaultValue = attributeData.ConstructorArguments.First().Value;
return true;
}
}

private RefConversion NeedsVariableForArgument(VBasic.Syntax.ArgumentSyntax node, RefKind refKind)
Expand Down
48 changes: 48 additions & 0 deletions Tests/CSharp/MemberTests/MemberTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4049,4 +4049,52 @@ public static int StaticTestProperty
}
}");
}

[Fact]
public async Task TestMissingByRefArgumentWithNoExplicitDefaultValueAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"Imports System.Runtime.InteropServices

Class MissingByRefArgumentWithNoExplicitDefaultValue
Sub S()
ByRefNoDefault()
OptionalByRefNoDefault()
OptionalByRefWithDefault()
End Sub

Private Sub ByRefNoDefault(ByRef str1 As String) : End Sub
Private Sub OptionalByRefNoDefault(<[Optional]> ByRef str2 As String) : End Sub
Private Sub OptionalByRefWithDefault(<[Optional], DefaultParameterValue(""a"")> ByRef str3 As String) : End Sub
End Class", @"using System.Runtime.InteropServices;

internal partial class MissingByRefArgumentWithNoExplicitDefaultValue
{
public void S()
{
ByRefNoDefault();
string argstr2 = default;
OptionalByRefNoDefault(str2: ref argstr2);
string argstr3 = ""a"";
OptionalByRefWithDefault(str3: ref argstr3);
}

private void ByRefNoDefault(ref string str1)
{
}
private void OptionalByRefNoDefault([Optional] ref string str2)
{
}
private void OptionalByRefWithDefault([Optional][DefaultParameterValue(""a"")] ref string str3)
{
}
}
3 source compilation errors:
BC30455: Argument not specified for parameter 'str1' of 'Private Sub ByRefNoDefault(ByRef str1 As String)'.
BC30455: Argument not specified for parameter 'str2' of 'Private Sub OptionalByRefNoDefault(ByRef str2 As String)'.
BC30455: Argument not specified for parameter 'str3' of 'Private Sub OptionalByRefWithDefault(ByRef str3 As String)'.
1 target compilation errors:
CS7036: There is no argument given that corresponds to the required formal parameter 'str1' of 'MissingByRefArgumentWithNoExplicitDefaultValue.ByRefNoDefault(ref string)'
");
}
}
Loading