Skip to content

Commit

Permalink
Made changes to the Code Generation Service to support local function…
Browse files Browse the repository at this point in the history
… statement syntax for the addition of the parameters in the declaration
  • Loading branch information
Lavanya Guruswamy committed Jul 30, 2019
1 parent 51e3ea7 commit 2b88633
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 25 deletions.
39 changes: 28 additions & 11 deletions src/Features/CSharp/Portable/MakeLocalFunctionStatic/GetCaptures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@




namespace Microsoft.CodeAnalysis.CSharp.GetCaptures
{
[Shared]
Expand All @@ -28,6 +29,7 @@ internal class GetCaptures : ILanguageService
private static readonly SyntaxGenerator s_generator = CSharpSyntaxGenerator.Instance;



internal async Task<Solution> CreateParameterSymbolAsync(Document document, LocalFunctionStatementSyntax localfunction, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(true);
Expand All @@ -37,19 +39,23 @@ internal async Task<Solution> 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);




Expand All @@ -58,6 +64,7 @@ internal async Task<Solution> CreateParameterSymbolAsync(Document document, Loca




//keep trivia
foreach (var referenceSymbol in arrayNode)
{
Expand All @@ -68,63 +75,76 @@ internal async Task<Solution> CreateParameterSymbolAsync(Document document, Loca




var invocation = (syntaxNode as IdentifierNameSyntax).Parent as InvocationExpressionSyntax;
if (invocation == null)
{
return document.Project.Solution;
}



var arg_List = invocation.ArgumentList;
List<ArgumentSyntax> x = new List<ArgumentSyntax>();



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<IParameterSymbol> DetermineParameters(ImmutableArray<ISymbol> captures)
{
var parameters = ArrayBuilder<IParameterSymbol>.GetInstance();



foreach (var symbol in captures)
{




var type = symbol.GetSymbolType();
parameters.Add(CodeGenerationSymbolFactory.CreateParameterSymbol(
attributes: default,
Expand All @@ -135,31 +155,28 @@ static ImmutableArray<IParameterSymbol> DetermineParameters(ImmutableArray<ISymb
}



return parameters.ToImmutableAndFree();



}



}



internal SyntaxNode GenerateArgument(IParameterSymbol p, string name, bool shouldUseNamedArguments = false)
=> s_generator.Argument(shouldUseNamedArguments ? name : null, p.RefKind, name.ToIdentifierName());

internal static Task<IEnumerable<ReferencedSymbol>> 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());


}



}


Original file line number Diff line number Diff line change
Expand Up @@ -278,21 +278,36 @@ public override TDeclarationNode AddParameters<TDeclarationNode>(
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<TDeclarationNode>(finalMember);
}



private static BaseParameterListSyntax ParameterListHelper(IEnumerable<IParameterSymbol> 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)
Expand All @@ -302,16 +317,18 @@ public override TDeclarationNode AddParameters<TDeclarationNode>(
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<ParameterSyntax>(parameterNodesAndTokens));
var finalMember = memberDeclaration.WithParameterList(finalParameterList);

return Cast<TDeclarationNode>(finalMember);

var finalParameterList = currentParameterList.WithParameters(SyntaxFactory.SeparatedList<ParameterSyntax>(parameterNodesAndTokens));
return finalParameterList;
}

public override TDeclarationNode AddAttributes<TDeclarationNode>(
Expand Down

0 comments on commit 2b88633

Please sign in to comment.