| File: InlineHints\CSharpInlineParameterNameHintsService.cs | Web Access |
| Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.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; using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineHints; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp.InlineHints; /// <summary> /// The service to locate the positions in which the adornments should appear /// as well as associate the adornments back to the parameter name /// </summary> [ExportLanguageService(typeof(IInlineParameterNameHintsService), LanguageNames.CSharp), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class CSharpInlineParameterNameHintsService() : AbstractInlineParameterNameHintsService { protected override void AddAllParameterNameHintLocations( SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, SyntaxNode node, ArrayBuilder<(int position, SyntaxNode argument, IParameterSymbol? parameter, HintKind kind)> buffer, CancellationToken cancellationToken) { if (node is BaseArgumentListSyntax argumentList) { AddArguments(semanticModel, buffer, argumentList, cancellationToken); } else if (node is AttributeArgumentListSyntax attributeArgumentList) { AddArguments(semanticModel, buffer, attributeArgumentList, cancellationToken); } } private static void AddArguments( SemanticModel semanticModel, ArrayBuilder<(int position, SyntaxNode argument, IParameterSymbol? parameter, HintKind kind)> buffer, AttributeArgumentListSyntax argumentList, CancellationToken cancellationToken) { foreach (var argument in argumentList.Arguments) { if (argument.NameEquals != null || argument.NameColon != null) continue; var parameter = argument.DetermineParameter(semanticModel, cancellationToken: cancellationToken); buffer.Add((argument.Span.Start, argument, parameter, GetKind(argument.Expression))); } } private static void AddArguments( SemanticModel semanticModel, ArrayBuilder<(int position, SyntaxNode argument, IParameterSymbol? parameter, HintKind kind)> buffer, BaseArgumentListSyntax argumentList, CancellationToken cancellationToken) { // Ensure we don't add an inline parameter name hint using the same name already present on another argument. using var _ = PooledHashSet<string?>.GetInstance(out var presentNames); foreach (var argument in argumentList.Arguments) { if (argument is { NameColon.Name.Identifier.ValueText: string nameText }) presentNames.Add(nameText); } foreach (var argument in argumentList.Arguments) { if (argument.NameColon != null) continue; var parameter = argument.DetermineParameter(semanticModel, cancellationToken: cancellationToken); if (presentNames.Contains(parameter?.Name)) continue; buffer.Add((argument.Span.Start, argument, parameter, GetKind(argument.Expression))); } } private static HintKind GetKind(ExpressionSyntax arg) => arg switch { LiteralExpressionSyntax or InterpolatedStringExpressionSyntax => HintKind.Literal, ObjectCreationExpressionSyntax => HintKind.ObjectCreation, CastExpressionSyntax cast => GetKind(cast.Expression), PrefixUnaryExpressionSyntax prefix => GetKind(prefix.Operand), // Treat `expr!` the same as `expr` (i.e. treat `!` as if it's just trivia). PostfixUnaryExpressionSyntax(SyntaxKind.SuppressNullableWarningExpression) postfix => GetKind(postfix.Operand), _ => HintKind.Other, }; protected override bool IsIndexer(SyntaxNode node, IParameterSymbol parameter) { return node is BracketedArgumentListSyntax; } protected override string GetReplacementText(string parameterName) { var keywordKind = SyntaxFacts.GetKeywordKind(parameterName); var isReservedKeyword = SyntaxFacts.IsReservedKeyword(keywordKind); return (isReservedKeyword ? "@" : string.Empty) + parameterName + ": "; } }