From 2b886339e7e8cfe2bdae65c1d0c964ff3fd4fa1e Mon Sep 17 00:00:00 2001 From: Lavanya Guruswamy Date: Mon, 29 Jul 2019 17:42:28 -0700 Subject: [PATCH] Made changes to the Code Generation Service to support local function statement syntax for the addition of the parameters in the declaration --- .../MakeLocalFunctionStatic/GetCaptures.cs | 39 +++++++++++----- .../CSharpCodeGenerationService.cs | 45 +++++++++++++------ 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/GetCaptures.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/GetCaptures.cs index 117d62a0b635a..d980cda573938 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/GetCaptures.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/GetCaptures.cs @@ -18,6 +18,7 @@ + namespace Microsoft.CodeAnalysis.CSharp.GetCaptures { [Shared] @@ -28,6 +29,7 @@ internal class GetCaptures : ILanguageService private static readonly SyntaxGenerator s_generator = CSharpSyntaxGenerator.Instance; + internal async Task CreateParameterSymbolAsync(Document document, LocalFunctionStatementSyntax localfunction, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(true); @@ -37,19 +39,23 @@ internal async Task CreateParameterSymbolAsync(Document document, Loca } + var localFunctionSymbol = semanticModel.GetDeclaredSymbol(localfunction, cancellationToken); var dataFlow = semanticModel.AnalyzeDataFlow(localfunction); var captures = dataFlow.CapturedInside; + var parameters = DetermineParameters(captures); //should we set this equal to something? + //Finds all the call sites of the local function var workspace = document.Project.Solution.Workspace; - var arrayNode = await FindReferencesAsync(localFunctionSymbol, document.Project.Solution, cancellationToken: cancellationToken).ConfigureAwait(false); + var arrayNode = await SymbolFinder.FindReferencesAsync(localFunctionSymbol, document.Project.Solution, cancellationToken: cancellationToken).ConfigureAwait(false); + @@ -58,6 +64,7 @@ internal async Task CreateParameterSymbolAsync(Document document, Loca + //keep trivia foreach (var referenceSymbol in arrayNode) { @@ -68,6 +75,7 @@ internal async Task CreateParameterSymbolAsync(Document document, Loca + var invocation = (syntaxNode as IdentifierNameSyntax).Parent as InvocationExpressionSyntax; if (invocation == null) { @@ -75,56 +83,68 @@ internal async Task CreateParameterSymbolAsync(Document document, Loca } + var arg_List = invocation.ArgumentList; List x = new List(); + foreach (var parameter in parameters) { + var newArgument = GenerateArgument(parameter, parameter.Name, false); + x.Add(newArgument as ArgumentSyntax); } + var newArgList = arg_List.WithArguments(arg_List.Arguments.AddRange(x)); var newInvocation = invocation.WithArgumentList(newArgList); + dict.Add(invocation, newInvocation); } } + //Updates the declaration with the variables passed in - var newLC = CodeGenerator.AddParameterDeclarations(localfunction, parameters, workspace); - dict.Add(localfunction, newLC); + var newLF = CodeGenerator.AddParameterDeclarations(localfunction, parameters, workspace); + dict.Add(localfunction, newLF); var syntaxTree = localfunction.SyntaxTree; + var newRoot = syntaxTree.GetRoot(cancellationToken).ReplaceNodes(dict.Keys, (invocation, _) => dict[invocation]); var newDocument = document.WithSyntaxRoot(newRoot); + return newDocument.Project.Solution; + //Gets all the variables in the local function and its attributes and puts them in an array static ImmutableArray DetermineParameters(ImmutableArray captures) { var parameters = ArrayBuilder.GetInstance(); + foreach (var symbol in captures) { + var type = symbol.GetSymbolType(); parameters.Add(CodeGenerationSymbolFactory.CreateParameterSymbol( attributes: default, @@ -135,25 +155,24 @@ static ImmutableArray DetermineParameters(ImmutableArray s_generator.Argument(shouldUseNamedArguments ? name : null, p.RefKind, name.ToIdentifierName()); - internal static Task> FindReferencesAsync(ISymbol symbol, Solution solution, CancellationToken cancellationToken = default) - { - return FindReferencesAsync(symbol, solution, cancellationToken: cancellationToken); - } - internal SyntaxNode GenerateArgument(IParameterSymbol p, string name, bool shouldUseNamedArguments = false) - => s_generator.Argument(shouldUseNamedArguments ? name : null, p.RefKind, name.ToIdentifierName()); } @@ -161,5 +180,3 @@ internal SyntaxNode GenerateArgument(IParameterSymbol p, string name, bool shoul } - - diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs index fa0b34d65ae5d..4e48df3995cd7 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs @@ -278,21 +278,36 @@ public override TDeclarationNode AddParameters( CodeGenerationOptions options, CancellationToken cancellationToken) { - var memberDeclaration = destinationMember as MemberDeclarationSyntax; - if (memberDeclaration == null) - { - return destinationMember; - } + SyntaxNode finalMember; - var currentParameterList = memberDeclaration.GetParameterList(); - if (currentParameterList == null) + + //Also supports local function statement syntax + switch (destinationMember) { - return destinationMember; + case MemberDeclarationSyntax memberDeclaration: + finalMember = memberDeclaration.WithParameterList(ParameterListHelper(parameters, options, memberDeclaration.GetParameterList())); + break; + case LocalFunctionStatementSyntax localfunction: + finalMember = localfunction.WithParameterList((ParameterListSyntax)ParameterListHelper(parameters, options, localfunction.ParameterList)); + break; + default: + return destinationMember; } - var currentParamsCount = currentParameterList.Parameters.Count; - var seenOptional = currentParamsCount > 0 && currentParameterList.Parameters[currentParamsCount - 1].Default != null; - var isFirstParam = currentParamsCount == 0; + + + return Cast(finalMember); + } + + + + private static BaseParameterListSyntax ParameterListHelper(IEnumerable parameters, CodeGenerationOptions options, BaseParameterListSyntax currentParameterList) + { + int currentParamsCount = currentParameterList.Parameters.Count; + bool seenOptional = currentParamsCount > 0 && currentParameterList.Parameters[currentParamsCount - 1].Default != null; + bool isFirstParam = currentParamsCount == 0; + + var parameterNodesAndTokens = currentParameterList.Parameters.GetWithSeparators().ToList(); foreach (var parameter in parameters) @@ -302,16 +317,18 @@ public override TDeclarationNode AddParameters( parameterNodesAndTokens.Add(SyntaxFactory.Token(SyntaxKind.CommaToken)); } + + var parameterSyntax = ParameterGenerator.GetParameter(parameter, options, isExplicit: false, isFirstParam: isFirstParam, seenOptional: seenOptional); parameterNodesAndTokens.Add(parameterSyntax); isFirstParam = false; seenOptional = seenOptional || parameterSyntax.Default != null; } - var finalParameterList = currentParameterList.WithParameters(SyntaxFactory.SeparatedList(parameterNodesAndTokens)); - var finalMember = memberDeclaration.WithParameterList(finalParameterList); - return Cast(finalMember); + + var finalParameterList = currentParameterList.WithParameters(SyntaxFactory.SeparatedList(parameterNodesAndTokens)); + return finalParameterList; } public override TDeclarationNode AddAttributes(