Skip to content

Commit

Permalink
use ref arguments if ByRef parameter was involved
Browse files Browse the repository at this point in the history
  • Loading branch information
Timur Kelman authored and Timur Kelman committed Jul 24, 2024
1 parent f0eb3f7 commit 0294eaf
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 11 deletions.
2 changes: 1 addition & 1 deletion CodeConverter/CSharp/CommonConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public bool ShouldPreferExplicitType(VBSyntax.ExpressionSyntax exp,
equalsValueClauseSyntax = null;
} else {
var returnBlock = SyntaxFactory.Block(SyntaxFactory.ReturnStatement(adjustedInitializerExpr));
_typeContext.PerScopeState.Hoist(new HoistedParameterlessFunction(GetInitialValueFunctionName(vbName), csTypeSyntax, returnBlock));
_typeContext.PerScopeState.Hoist(new HoistedFunction(GetInitialValueFunctionName(vbName), csTypeSyntax, returnBlock, null));
equalsValueClauseSyntax = null;
}
} else {
Expand Down
38 changes: 35 additions & 3 deletions CodeConverter/CSharp/ExpressionNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,9 +1174,41 @@ private async Task<InvocationExpressionSyntax> HoistAndCallLocalFunctionAsync(VB
statements.Concat(SyntaxFactory.ReturnStatement(ValidSyntaxFactory.IdentifierName(retVariableName)).Yield())
);
var returnType = CommonConversions.GetTypeSyntax(invocationSymbol.ReturnType);

var localFunc = _typeContext.PerScopeState.Hoist(new HoistedParameterlessFunction(localFuncName, returnType, block));
return SyntaxFactory.InvocationExpression(localFunc.TempIdentifier, SyntaxFactory.ArgumentList());

//any argument that's a ByRef parameter of the parent method needs to be passed as a ref parameter to the local function (to avoid error CS1628)
var refParametersOfParent = GetRefParameters(invocation.ArgumentList);
var (args, @params) = CreateArgumentsAndParametersLists(refParametersOfParent);

var localFunc = _typeContext.PerScopeState.Hoist(new HoistedFunction(localFuncName, returnType, block, SyntaxFactory.ParameterList(@params)));
return SyntaxFactory.InvocationExpression(localFunc.TempIdentifier, SyntaxFactory.ArgumentList(args));

List<IParameterSymbol> GetRefParameters(VBSyntax.ArgumentListSyntax argumentList)
{
var result = new List<IParameterSymbol>();
if (argumentList is null) return result;

foreach (var arg in argumentList.Arguments) {
if (_semanticModel.GetSymbolInfo(arg.GetExpression()).Symbol is not IParameterSymbol p) continue;
if (p.RefKind != RefKind.None) {
result.Add(p);
}
}

return result;
}

(SeparatedSyntaxList<ArgumentSyntax>, SeparatedSyntaxList<ParameterSyntax>) CreateArgumentsAndParametersLists(List<IParameterSymbol> parameterSymbols)
{
var arguments = new List<ArgumentSyntax>();
var parameters = new List<ParameterSyntax>();
foreach (var p in parameterSymbols) {
var arg = (ArgumentSyntax)CommonConversions.CsSyntaxGenerator.Argument(p.RefKind, SyntaxFactory.IdentifierName(p.Name));
arguments.Add(arg);
var par = (ParameterSyntax)CommonConversions.CsSyntaxGenerator.ParameterDeclaration(p);
parameters.Add(par);
}
return (SyntaxFactory.SeparatedList(arguments), SyntaxFactory.SeparatedList(parameters));
}
}

private bool RequiresLocalFunction(VBSyntax.InvocationExpressionSyntax invocation, IMethodSymbol invocationSymbol)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@

namespace ICSharpCode.CodeConverter.CSharp;

internal class HoistedParameterlessFunction : IHoistedNode
internal class HoistedFunction : IHoistedNode
{
private readonly TypeSyntax _returnType;
private readonly BlockSyntax _block;
private readonly ParameterListSyntax _parameters;

public string Id { get; }
public string Prefix { get; }

public HoistedParameterlessFunction(string localFuncName, TypeSyntax returnType, BlockSyntax block)
public HoistedFunction(string localFuncName, TypeSyntax returnType, BlockSyntax block, ParameterListSyntax parameters)
{
Id = $"hs{Guid.NewGuid().ToString("N")}";
Prefix = localFuncName;
_returnType = returnType;
_block = block;
_parameters = parameters;
}

public IdentifierNameSyntax TempIdentifier => ValidSyntaxFactory.IdentifierName(Id).WithAdditionalAnnotations(PerScopeState.AdditionalLocalAnnotation);
public LocalFunctionStatementSyntax AsLocalFunction(string functionName) => SyntaxFactory.LocalFunctionStatement(_returnType, SyntaxFactory.Identifier(functionName)).WithBody(_block);
public MethodDeclarationSyntax AsInstanceMethod(string functionName) => ValidSyntaxFactory.CreateParameterlessMethod(functionName, _returnType, _block);
public LocalFunctionStatementSyntax AsLocalFunction(string functionName) => SyntaxFactory.LocalFunctionStatement(_returnType, SyntaxFactory.Identifier(functionName)).WithParameterList(_parameters).WithBody(_block);
public MethodDeclarationSyntax AsInstanceMethod(string functionName) => ValidSyntaxFactory.CreateMethod(functionName, _returnType, _parameters, _block);
}
4 changes: 2 additions & 2 deletions CodeConverter/CSharp/PerScopeState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ private StatementSyntax[] GetPostStatements()
.ToArray();
}

public IReadOnlyCollection<HoistedParameterlessFunction> GetParameterlessFunctions()
public IReadOnlyCollection<HoistedFunction> GetParameterlessFunctions()
{
return _hoistedNodesPerScope.Peek().OfType<HoistedParameterlessFunction>().ToArray();
return _hoistedNodesPerScope.Peek().OfType<HoistedFunction>().ToArray();
}

public IReadOnlyCollection<HoistedFieldFromVbStaticVariable> GetFields()
Expand Down
9 changes: 8 additions & 1 deletion CodeConverter/CSharp/ValidSyntaxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,17 @@ expressionSyntax is IdentifierNameSyntax ||
}

public static MethodDeclarationSyntax CreateParameterlessMethod(string newMethodName, TypeSyntax type, BlockSyntax body)
{
var parameterList = SyntaxFactory.ParameterList();
return CreateMethod(newMethodName, type, parameterList, body);
}

public static MethodDeclarationSyntax CreateMethod(string newMethodName, TypeSyntax type, ParameterListSyntax parameterList, BlockSyntax body)
{
var modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword));
var typeConstraints = SyntaxFactory.List<TypeParameterConstraintClauseSyntax>();
var parameterList = SyntaxFactory.ParameterList();
parameterList ??= SyntaxFactory.ParameterList();

var methodAttrs = SyntaxFactory.List<AttributeListSyntax>();

ArrowExpressionClauseSyntax arrowExpression = null;
Expand Down

0 comments on commit 0294eaf

Please sign in to comment.