public override TDeclarationNode AddParameters <TDeclarationNode>( TDeclarationNode destination, IEnumerable <IParameterSymbol> parameters, CSharpCodeGenerationOptions options, CancellationToken cancellationToken) { var currentParameterList = destination.GetParameterList(); var parameterCount = currentParameterList != null ? currentParameterList.Parameters.Count : 0; var seenOptional = currentParameterList != null && parameterCount > 0 && currentParameterList.Parameters[^ 1].Default != null; var isFirstParam = parameterCount == 0; var editor = new SyntaxEditor(destination, CSharpSyntaxGenerator.Instance); foreach (var parameter in parameters) { var parameterSyntax = ParameterGenerator.GetParameter(parameter, options, isExplicit: false, isFirstParam: isFirstParam, seenOptional: seenOptional); AddParameterEditor.AddParameter( CSharpSyntaxFacts.Instance, editor, destination, parameterCount, parameterSyntax, cancellationToken); parameterCount++; isFirstParam = false; seenOptional = seenOptional || parameterSyntax.Default != null; } var finalMember = editor.GetChangedRoot(); return(Cast <TDeclarationNode>(finalMember)); }
/// <summary> /// Adds a parameter to a method. /// </summary> /// <param name="newParameterIndex"><see langword="null"/> to add as the final parameter</param> /// <returns></returns> public static async Task <Solution> AddParameterAsync( Document invocationDocument, IMethodSymbol method, ITypeSymbol newParameterType, RefKind refKind, string parameterName, int?newParameterIndex, bool fixAllReferences, CancellationToken cancellationToken) { var solution = invocationDocument.Project.Solution; var referencedSymbols = fixAllReferences ? await FindMethodDeclarationReferencesAsync(invocationDocument, method, cancellationToken).ConfigureAwait(false) : method.GetAllMethodSymbolsOfPartialParts(); var anySymbolReferencesNotInSource = referencedSymbols.Any(symbol => !symbol.IsFromSource()); var locationsInSource = referencedSymbols.Where(symbol => symbol.IsFromSource()); // Indexing Locations[0] is valid because IMethodSymbols have one location at most // and IsFromSource() tests if there is at least one location. var locationsByDocument = locationsInSource.ToLookup(declarationLocation => solution.GetRequiredDocument(declarationLocation.Locations[0].SourceTree !)); foreach (var documentLookup in locationsByDocument) { var document = documentLookup.Key; var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(syntaxRoot, solution.Workspace.Services); var generator = editor.Generator; foreach (var methodDeclaration in documentLookup) { var methodNode = syntaxRoot.FindNode(methodDeclaration.Locations[0].SourceSpan, getInnermostNodeForTie: true); var existingParameters = generator.GetParameters(methodNode); var insertionIndex = newParameterIndex ?? existingParameters.Count; // if the preceding parameter is optional, the new parameter must also be optional // see also BC30202 and CS1737 var parameterMustBeOptional = insertionIndex > 0 && syntaxFacts.GetDefaultOfParameter(existingParameters[insertionIndex - 1]) != null; var parameterSymbol = CreateParameterSymbol( methodDeclaration, newParameterType, refKind, parameterMustBeOptional, parameterName); var argumentInitializer = parameterMustBeOptional ? generator.DefaultExpression(newParameterType) : null; var parameterDeclaration = generator.ParameterDeclaration(parameterSymbol, argumentInitializer) .WithAdditionalAnnotations(Formatter.Annotation); if (anySymbolReferencesNotInSource && methodDeclaration == method) { parameterDeclaration = parameterDeclaration.WithAdditionalAnnotations( ConflictAnnotation.Create(FeaturesResources.Related_method_signatures_found_in_metadata_will_not_be_updated)); } if (method.MethodKind == MethodKind.ReducedExtension && insertionIndex < existingParameters.Count) { insertionIndex++; } AddParameterEditor.AddParameter(syntaxFacts, editor, methodNode, insertionIndex, parameterDeclaration, cancellationToken); } var newRoot = editor.GetChangedRoot(); solution = solution.WithDocumentSyntaxRoot(document.Id, newRoot); } return(solution); }