// 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.Collections.Generic; using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Formatting; internal sealed partial class TriviaDataFactory { /// <summary> /// represents a general trivia between two tokens. slightly more expensive than others since it /// needs to calculate stuff unlike other cases /// </summary> private sealed class ComplexTrivia : AbstractComplexTrivia { public ComplexTrivia(LineFormattingOptions options, TreeData treeInfo, SyntaxToken token1, SyntaxToken token2) : base(options, treeInfo, token1, token2) { } protected override void ExtractLineAndSpace(string text, out int lines, out int spaces) => text.ProcessTextBetweenTokens(this.TreeInfo, this.Token1, this.Options.TabSize, out lines, out spaces); protected override TriviaData CreateComplexTrivia(int line, int space) => CreateModifiedComplexTrivia(line, space); protected override TriviaData CreateComplexTrivia(int line, int space, int indentation) => CreateModifiedComplexTrivia(line, space); private TriviaData CreateModifiedComplexTrivia(int line, int space) => new ModifiedComplexTrivia(this.Options, this, line, space); protected override TriviaDataWithList Format( FormattingContext context, ChainedFormattingRules formattingRules, int lines, int spaces, CancellationToken cancellationToken) { return new FormattedComplexTrivia(context, formattingRules, this.Token1, this.Token2, lines, spaces, this.OriginalString, cancellationToken); } protected override bool ContainsSkippedTokensOrText(TriviaList list) => CodeShapeAnalyzer.ContainsSkippedTokensOrText(list); private bool ShouldFormat(FormattingContext context) { var commonToken1 = this.Token1; var commonToken2 = this.Token2; var formatSpanEnd = commonToken2.Kind() == SyntaxKind.None ? commonToken1.Span.End : commonToken2.Span.Start; var span = TextSpan.FromBounds(commonToken1.Span.End, formatSpanEnd); if (context.IsSpacingSuppressed(span, TreatAsElastic)) { return false; } var triviaList = new TriviaList(commonToken1.TrailingTrivia, commonToken2.LeadingTrivia); Contract.ThrowIfFalse(triviaList.Count > 0); // okay, now, check whether we need or are able to format noisy tokens if (ContainsSkippedTokensOrText(triviaList)) { return false; } if (!this.SecondTokenIsFirstTokenOnLine) { return CodeShapeAnalyzer.ShouldFormatSingleLine(triviaList); } Debug.Assert(this.SecondTokenIsFirstTokenOnLine); if (Options.UseTabs) { return true; } var firstTriviaInTree = this.Token1.Kind() == SyntaxKind.None; return CodeShapeAnalyzer.ShouldFormatMultiLine(context, firstTriviaInTree, triviaList); } public override void Format( FormattingContext context, ChainedFormattingRules formattingRules, Action<int, TokenStream, TriviaData> formattingResultApplier, CancellationToken cancellationToken, int tokenPairIndex = TokenPairIndexNotNeeded) { if (!ShouldFormat(context)) { return; } formattingResultApplier(tokenPairIndex, context.TokenStream, Format(context, formattingRules, this.LineBreaks, this.Spaces, cancellationToken)); } public override SyntaxTriviaList GetTriviaList(CancellationToken cancellationToken) => throw new NotImplementedException(); public override IEnumerable<TextChange> GetTextChanges(TextSpan span) => throw new NotImplementedException(); } } |