@@ -408,18 +408,21 @@ public override async Task<CSharpSyntaxNode> VisitSimpleArgument(VBasic.Syntax.S
408408 SyntaxToken token = default ( SyntaxToken ) ;
409409 string argName = null ;
410410 RefKind refKind = RefKind . None ;
411- AdditionalLocal local = null ;
411+ AdditionalDeclaration local = null ;
412412 if ( symbol is IMethodSymbol methodSymbol ) {
413413 var parameters = ( CommonConversions . GetCsOriginalSymbolOrNull ( methodSymbol . OriginalDefinition ) ?? methodSymbol ) . GetParameters ( ) ;
414414 var refType = GetRefType ( node , argList , parameters , out argName , out refKind ) ;
415415 var expression = CommonConversions . TypeConversionAnalyzer . AddExplicitConversion ( node . Expression , ( ExpressionSyntax ) await node . Expression . AcceptAsync ( TriviaConvertingExpressionVisitor ) , defaultToCast : refKind != RefKind . None ) ;
416416
417+ string prefix = $ "arg{ argName } ";
417418 if ( refType != RefConversion . Inline ) {
418419 var expressionTypeInfo = _semanticModel . GetTypeInfo ( node . Expression ) ;
419420 bool useVar = expressionTypeInfo . Type ? . Equals ( expressionTypeInfo . ConvertedType ) == true && ! CommonConversions . ShouldPreferExplicitType ( node . Expression , expressionTypeInfo . ConvertedType , out var _ ) ;
420421 var typeSyntax = CommonConversions . GetTypeSyntax ( expressionTypeInfo . ConvertedType , useVar ) ;
421- string prefix = $ "arg{ argName } ";
422- local = _additionalLocals . AddAdditionalLocal ( new AdditionalLocal ( prefix , expression , typeSyntax ) ) ;
422+ local = _additionalLocals . Hoist ( new AdditionalDeclaration ( prefix , expression , typeSyntax ) ) ;
423+ }
424+ if ( refType == RefConversion . PreAndPostAssignment ) {
425+ _additionalLocals . Hoist ( new AdditionalAssignment ( local . IdentifierName , expression ) ) ;
423426 }
424427 }
425428
@@ -815,6 +818,25 @@ public override async Task<CSharpSyntaxNode> VisitInvocationExpression(
815818 VBasic . Syntax . InvocationExpressionSyntax node )
816819 {
817820 var invocationSymbol = _semanticModel . GetSymbolInfo ( node ) . ExtractBestMatch < ISymbol > ( ) ;
821+ var withinLocalFunction = RequiresLocalFunction ( node , invocationSymbol as IMethodSymbol ) ;
822+ if ( withinLocalFunction ) {
823+ _additionalLocals . PushScope ( ) ;
824+ }
825+ try {
826+ var convertedInvocation = await ConvertInvocation ( node , invocationSymbol ) ;
827+ if ( withinLocalFunction ) {
828+
829+ }
830+ return await ConvertInvocation ( node , invocationSymbol ) ;
831+ } finally {
832+ if ( withinLocalFunction ) {
833+ _additionalLocals . PopScope ( ) ;
834+ }
835+ }
836+ }
837+
838+ private async Task < CSharpSyntaxNode > ConvertInvocation ( VBSyntax . InvocationExpressionSyntax node , ISymbol invocationSymbol )
839+ {
818840 var expressionSymbol = _semanticModel . GetSymbolInfo ( node . Expression ) . ExtractBestMatch < ISymbol > ( ) ;
819841 var expressionReturnType =
820842 expressionSymbol ? . GetReturnType ( ) ?? _semanticModel . GetTypeInfo ( node . Expression ) . Type ;
@@ -841,7 +863,6 @@ public override async Task<CSharpSyntaxNode> VisitInvocationExpression(
841863 }
842864 //TODO: Decide if the above override should be subject to the rest of this method's adjustments (probably)
843865
844- CreateLocalByRefFunction ( node , invocationSymbol ) ;
845866
846867 // VB doesn't have a specialized node for element access because the syntax is ambiguous. Instead, it just uses an invocation expression or dictionary access expression, then figures out using the semantic model which one is most likely intended.
847868 // https://github.com/dotnet/roslyn/blob/master/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb#L768
@@ -891,46 +912,52 @@ async Task<CSharpSyntaxNode> CreateElementAccess()
891912 }
892913 }
893914
894-
915+
895916 /// <summary>
896917 /// If we need a local function,
897918 /// </summary>
898919 /// <param name="invocation"></param>
899920 /// <param name="invocationSymbol"></param>
900921 /// <returns></returns>
901- private async Task < ( string Id , StatementSyntax FunctionDeclaration ) > CreateLocalByRefFunction ( VBSyntax . InvocationExpressionSyntax invocation , IMethodSymbol invocationSymbol )
902- {
903- var originalArgsWithRefTypes = invocation . ArgumentList . Arguments
904- . Select ( a => ( Arg : ( VBSyntax . SimpleArgumentSyntax ) a , RefType : GetRefType ( ( VBSyntax . SimpleArgumentSyntax ) a , invocation . ArgumentList , invocationSymbol . Parameters , out var argName , out var refKind ) , Name : argName , RefKind : refKind ) )
905- . ToArray ( ) ;
922+ //private async Task<(string Id, StatementSyntax FunctionDeclaration)> CreateLocalByRefFunction(VBSyntax.InvocationExpressionSyntax invocation, IMethodSymbol invocationSymbol)
923+ //{
924+ // RequiresLocalFunction(invocation, invocationSymbol);
925+
926+ // var localFuncName = $"local{invocationSymbol.Name}";
927+ // const string retVariableName = "ret";
928+ // var localFuncId = SyntaxFactory.IdentifierName(localFuncName);
929+ // // Need essentially the original invocation with any byref args swapped out for temporaries
930+ // var callAndStoreResult = CommonConversions.CreateLocalVariableDeclarationAndAssignment(retVariableName,
931+ // SyntaxFactory.InvocationExpression(expression,
932+ // );
933+
934+ // var block = SyntaxFactory.Block(
935+ // callAndStoreResult,
936+ // AssignStmt(expression, tempArg),
937+ // SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(retVariableName))
938+ // );
939+ // var localfunction = SyntaxFactory.LocalFunctionStatement(CommonConversions.GetTypeSyntax(invocationSymbol.ReturnType),
940+ // localFuncId.Identifier).WithBody(block);
941+ // return (localFuncName, localfunction);
942+ //}
943+
944+ private bool RequiresLocalFunction ( VBSyntax . InvocationExpressionSyntax invocation , IMethodSymbol invocationSymbol )
945+ {
946+ if ( invocationSymbol == null ) return false ;
906947
907- var isDefinitelyExecuted = IsDefinitelyExecutedInStatement ( invocation ) ;
908-
909- var localFuncName = $ "local{ invocationSymbol . Name } ";
910- const string retVariableName = "ret" ;
911- var localFuncId = SyntaxFactory . IdentifierName ( localFuncName ) ;
912- // Need essentially the original invocation with any byref args swapped out for temporaries
913- var callAndStoreResult = CommonConversions . CreateLocalVariableDeclarationAndAssignment ( retVariableName ,
914- SyntaxFactory . InvocationExpression ( expression ,
915- ) ;
948+ var originalArgsWithRefTypes = invocation . ArgumentList . Arguments
949+ . Select ( a => ( Arg : ( VBSyntax . SimpleArgumentSyntax ) a , RefType : GetRefType ( ( VBSyntax . SimpleArgumentSyntax ) a , invocation . ArgumentList , invocationSymbol . Parameters , out var argName , out var refKind ) , Name : argName , RefKind : refKind ) ) ;
916950
917- var block = SyntaxFactory. Block(
918- callAndStoreResult ,
919- AssignStmt ( expression , tempArg ) ,
920- SyntaxFactory . ReturnStatement ( SyntaxFactory . IdentifierName ( retVariableName ) )
921- ) ;
922- var localfunction = SyntaxFactory . LocalFunctionStatement ( CommonConversions . GetTypeSyntax ( invocationSymbol . ReturnType ) ,
923- localFuncId . Identifier ) . WithBody ( block ) ;
924- return ( localFuncName , localfunction ) ;
951+ return originalArgsWithRefTypes . Any ( x => x . RefType != RefConversion . Inline ) && ! IsDefinitelyExecutedInStatement ( invocation ) ;
925952 }
926953
927954 private static bool IsDefinitelyExecutedInStatement ( VBSyntax . InvocationExpressionSyntax invocation )
928955 {
929- VBSyntax . StatementSyntax parentStatement ;
956+ SyntaxNode parentStatement = invocation ;
930957 do {
931- parentStatement = invocation . GetAncestor < VBSyntax . StatementSyntax > ( ) ;
958+ parentStatement = parentStatement . GetAncestor < VBSyntax . StatementSyntax > ( ) ;
932959 } while ( parentStatement is VBSyntax . ElseIfStatementSyntax ) ;
933- return parentStatement . FollowProperty < SyntaxNode > ( n => n . ChildNodes ( ) . FirstOrDefault ( ) ) . Contains ( invocation ) ;
960+ return parentStatement . FollowProperty ( n => n . ChildNodes ( ) . FirstOrDefault ( ) ) . Contains ( invocation ) ;
934961 }
935962
936963 public override async Task < CSharpSyntaxNode > VisitSingleLineLambdaExpression ( VBasic . Syntax . SingleLineLambdaExpressionSyntax node )
@@ -1360,12 +1387,13 @@ private IEnumerable<ArgumentSyntax> GetAdditionalRequiredArgs(ISymbol invocation
13601387 private ArgumentSyntax CreateOptionalRefArg ( IParameterSymbol p )
13611388 {
13621389 string prefix = $ "arg{ p . Name } ";
1363- var local = _additionalLocals . AddAdditionalLocal ( new AdditionalLocal ( prefix , CommonConversions . Literal ( p . ExplicitDefaultValue ) , CommonConversions . GetTypeSyntax ( p . Type ) ) ) ;
1390+ var local = _additionalLocals . Hoist ( new AdditionalDeclaration ( prefix , CommonConversions . Literal ( p . ExplicitDefaultValue ) , CommonConversions . GetTypeSyntax ( p . Type ) ) ) ;
13641391 return ( ArgumentSyntax ) CommonConversions . CsSyntaxGenerator . Argument ( p . Name , p . RefKind , local . IdentifierName ) ;
13651392 }
13661393
13671394 private RefConversion NeedsVariableForArgument ( VBasic . Syntax . SimpleArgumentSyntax node , RefKind refKind )
13681395 {
1396+ if ( refKind == RefKind . None ) return RefConversion . Inline ;
13691397 bool isIdentifier = node . Expression is VBasic . Syntax . IdentifierNameSyntax ;
13701398 bool isMemberAccess = node . Expression is VBasic . Syntax . MemberAccessExpressionSyntax ;
13711399
0 commit comments