| File: Wrapping\SeparatedSyntaxList\CSharpArgumentWrapper.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.Linq; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Wrapping; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Wrapping.SeparatedSyntaxList; internal sealed partial class CSharpArgumentWrapper : AbstractCSharpSeparatedSyntaxListWrapper<BaseArgumentListSyntax, ArgumentSyntax> { protected override string Align_wrapped_items => FeaturesResources.Align_wrapped_arguments; protected override string Indent_all_items => FeaturesResources.Indent_all_arguments; protected override string Indent_wrapped_items => FeaturesResources.Indent_wrapped_arguments; protected override string Unwrap_all_items => FeaturesResources.Unwrap_all_arguments; protected override string Unwrap_and_indent_all_items => FeaturesResources.Unwrap_and_indent_all_arguments; protected override string Unwrap_list => FeaturesResources.Unwrap_argument_list; protected override string Wrap_every_item => FeaturesResources.Wrap_every_argument; protected override string Wrap_long_list => FeaturesResources.Wrap_long_argument_list; public override bool Supports_UnwrapGroup_WrapFirst_IndentRest => true; public override bool Supports_WrapEveryGroup_UnwrapFirst => true; public override bool Supports_WrapLongGroup_UnwrapFirst => true; protected override bool ShouldMoveOpenBraceToNewLine(SyntaxWrappingOptions options) => false; protected override bool ShouldMoveCloseBraceToNewLine => false; protected override SyntaxToken FirstToken(BaseArgumentListSyntax listSyntax) => listSyntax.GetOpenToken(); protected override SyntaxToken LastToken(BaseArgumentListSyntax listSyntax) => listSyntax.GetCloseToken(); protected override SeparatedSyntaxList<ArgumentSyntax> GetListItems(BaseArgumentListSyntax listSyntax) => listSyntax.Arguments; protected override BaseArgumentListSyntax? TryGetApplicableList(SyntaxNode node) => node switch { InvocationExpressionSyntax invocationExpression => invocationExpression.ArgumentList, ElementAccessExpressionSyntax elementAccessExpression => elementAccessExpression.ArgumentList, BaseObjectCreationExpressionSyntax objectCreationExpression => objectCreationExpression.ArgumentList, ConstructorInitializerSyntax constructorInitializer => constructorInitializer.ArgumentList, PrimaryConstructorBaseTypeSyntax baseTypeSyntax => baseTypeSyntax.ArgumentList, _ => null, }; protected override bool PositionIsApplicable( SyntaxNode root, int position, SyntaxNode declaration, bool containsSyntaxError, BaseArgumentListSyntax listSyntax) { if (containsSyntaxError) return false; var startToken = listSyntax.GetFirstToken(); if (declaration is InvocationExpressionSyntax or ElementAccessExpressionSyntax) { // If we have something like Foo(...) or this.Foo(...) allow anywhere in the Foo(...) // section. var expr = (declaration as InvocationExpressionSyntax)?.Expression ?? ((ElementAccessExpressionSyntax)declaration).Expression; var name = TryGetInvokedName(expr); startToken = name == null ? listSyntax.GetFirstToken() : name.GetFirstToken(); } else if (declaration is BaseObjectCreationExpressionSyntax) { // allow anywhere in `new Foo(...)` startToken = declaration.GetFirstToken(); } else if (declaration is ConstructorInitializerSyntax constructorInitializer) { // allow anywhere in `this(...)` or `base(...)` startToken = constructorInitializer.ThisOrBaseKeyword; } else if (declaration is PrimaryConstructorBaseTypeSyntax baseTypeSyntax) { // allow anywhere in `BaseClass(...)` startToken = baseTypeSyntax.GetFirstToken(); } var endToken = listSyntax.GetLastToken(); var span = TextSpan.FromBounds(startToken.SpanStart, endToken.Span.End); if (!span.IntersectsWith(position)) return false; // allow anywhere in the arg list, as long we don't end up walking through something // complex like a lambda/anonymous function. var token = root.FindToken(position); if (token.GetRequiredParent().Ancestors().Contains(listSyntax)) { for (var current = token.Parent; current != listSyntax; current = current?.Parent) { if (CSharpSyntaxFacts.Instance.IsAnonymousFunctionExpression(current)) return false; } } return true; } private static ExpressionSyntax? TryGetInvokedName(ExpressionSyntax expr) { // `Foo(...)`. Allow up through the 'Foo' portion if (expr is NameSyntax name) return name; // `this[...]`. Allow up through the 'this' token. if (expr is ThisExpressionSyntax or BaseExpressionSyntax) return expr; // expr.Foo(...) or expr?.Foo(...) // All up through the 'Foo' portion. // // Otherwise, only allow in the arg list. return (expr as MemberAccessExpressionSyntax)?.Name ?? (expr as MemberBindingExpressionSyntax)?.Name; } }