| File: NameTupleElement\AbstractNameTupleElementCodeRefactoringProvider.cs | Web Access |
| Project: src\roslyn\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.NameTupleElement; internal abstract class AbstractNameTupleElementCodeRefactoringProvider<TArgumentSyntax, TTupleExpressionSyntax> : CodeRefactoringProvider where TArgumentSyntax : SyntaxNode where TTupleExpressionSyntax : SyntaxNode { protected abstract TArgumentSyntax WithName(TArgumentSyntax argument, string argumentName); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, span, cancellationToken) = context; var (_, argument, elementName) = await TryGetArgumentInfoAsync(document, span, cancellationToken).ConfigureAwait(false); if (elementName == null) { return; } context.RegisterRefactoring( CodeAction.Create( string.Format(FeaturesResources.Add_tuple_element_name_0, elementName), c => AddNamedElementAsync(document, span, cancellationToken), nameof(FeaturesResources.Add_tuple_element_name_0) + "_" + elementName), argument.Span); } private static async Task<(SyntaxNode root, TArgumentSyntax argument, string argumentName)> TryGetArgumentInfoAsync( Document document, TextSpan span, CancellationToken cancellationToken) { if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles) { return default; } var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>(); var potentialArguments = await document.GetRelevantNodesAsync<TArgumentSyntax>(span, cancellationToken).ConfigureAwait(false); var argument = potentialArguments.FirstOrDefault(n => n?.Parent is TTupleExpressionSyntax); if (argument == null || !syntaxFacts.IsSimpleArgument(argument)) { return default; } var tuple = (TTupleExpressionSyntax)argument.GetRequiredParent(); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel.GetTypeInfo(tuple, cancellationToken).ConvertedType is not INamedTypeSymbol tupleType) { return default; } syntaxFacts.GetPartsOfTupleExpression<TArgumentSyntax>(tuple, out _, out var arguments, out _); var argumentIndex = arguments.IndexOf(argument); var elements = tupleType.TupleElements; if (elements.IsDefaultOrEmpty || argumentIndex >= elements.Length) { return default; } var element = elements[argumentIndex]; if (element.Equals(element.CorrespondingTupleField)) { return default; } var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return (root, argument, element.Name); } private async Task<Document> AddNamedElementAsync(Document document, TextSpan span, CancellationToken cancellationToken) { var (root, argument, elementName) = await TryGetArgumentInfoAsync(document, span, cancellationToken).ConfigureAwait(false); var newArgument = WithName(argument, elementName).WithTriviaFrom(argument); var newRoot = root.ReplaceNode(argument, newArgument); return document.WithSyntaxRoot(newRoot); } }