private IFormattingResult FormatMergedSpan( SyntaxNode node, AnalyzerConfigOptions options, IEnumerable <AbstractFormattingRule> rules, IList <TextSpan> spansToFormat, CancellationToken cancellationToken ) { var spanToFormat = TextSpan.FromBounds( spansToFormat[0].Start, spansToFormat[spansToFormat.Count - 1].End ); var pair = node.ConvertToTokenPair(spanToFormat); if (node.IsInvalidTokenRange(pair.Item1, pair.Item2)) { return(CreateAggregatedFormattingResult( node, SpecializedCollections.EmptyList <AbstractFormattingResult>() )); } // more expensive case var result = Format(node, options, rules, pair.Item1, pair.Item2, cancellationToken); return(CreateAggregatedFormattingResult( node, new List <AbstractFormattingResult>(1) { result }, SimpleIntervalTree.Create(new TextSpanIntervalIntrospector(), spanToFormat) )); }
/// <summary> /// Make sure annotations are positioned outside of any spans. If not, merge two adjacent spans to one. /// </summary> private IEnumerable <TextSpan> GetNonOverlappingSpans(ISyntaxFactsService syntaxFactsService, SyntaxNode root, IEnumerable <TextSpan> spans, CancellationToken cancellationToken) { // Create interval tree for spans var intervalTree = SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance, spans); // Find tokens that are outside of spans var tokenSpans = new List <TextSpan>(); foreach (var span in spans) { cancellationToken.ThrowIfCancellationRequested(); SyntaxToken startToken; SyntaxToken endToken; TextSpan spanAlignedToTokens = GetSpanAlignedToTokens(syntaxFactsService, root, span, out startToken, out endToken); SyntaxToken previousToken = startToken.GetPreviousToken(includeZeroWidth: true, includeSkipped: true, includeDirectives: true, includeDocumentationComments: true); SyntaxToken nextToken = endToken.GetNextToken(includeZeroWidth: true, includeSkipped: true, includeDirectives: true, includeDocumentationComments: true); // Make sure the previous and next tokens we found do not overlap with any existing spans. If they do, merge two spans. previousToken = (previousToken.RawKind == 0) ? root.GetFirstToken(includeZeroWidth: true) : previousToken; var start = intervalTree.GetOverlappingIntervals(previousToken.SpanStart, previousToken.Span.Length).Any() ? previousToken.SpanStart : startToken.SpanStart; nextToken = (nextToken.RawKind == 0) ? root.GetLastToken(includeZeroWidth: true) : nextToken; var end = intervalTree.GetOverlappingIntervals(nextToken.SpanStart, nextToken.Span.Length).Any() ? nextToken.Span.End : endToken.Span.End; tokenSpans.Add(TextSpan.FromBounds(start, end)); } return(tokenSpans.ToNormalizedSpans()); }
private SyntaxTreeState(bool completed, int?positionOfFirstReducingNullableDirective) { Completed = completed; PositionOfFirstReducingNullableDirective = positionOfFirstReducingNullableDirective; if (!completed) { IntervalTree = SimpleIntervalTree.Create(new TextSpanIntervalIntrospector(), Array.Empty <TextSpan>()); PossibleNullableImpactIntervalTree = SimpleIntervalTree.Create(new TextSpanIntervalIntrospector(), Array.Empty <TextSpan>()); } }
private static IEnumerable <SimpleIntervalTree <Tuple <int, int, string> > > CreateTrees(IEnumerable <Tuple <int, int, string> > values) { yield return(SimpleIntervalTree.Create(new TupleIntrospector <string>(), values)); var tree1 = SimpleIntervalTree.Create(new TupleIntrospector <string>()); foreach (var v in values) { tree1 = tree1.AddInterval(v); } yield return(tree1); }
private void Validate(TextSpan textSpan) { #if DEBUG if (nonOverlappingSpans == null) { nonOverlappingSpans = SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance); } // new span should not overlap with any span that we already have. Contract.Requires(!nonOverlappingSpans.GetOverlappingIntervals(textSpan.Start, textSpan.Length).Any()); nonOverlappingSpans = nonOverlappingSpans.AddInterval(textSpan); #endif }
protected override SyntaxNode Rewriter( Dictionary <ValueTuple <SyntaxToken, SyntaxToken>, TriviaData> changeMap, CancellationToken cancellationToken ) { var rewriter = new TriviaRewriter( this.TreeInfo.Root, SimpleIntervalTree.Create(new TextSpanIntervalIntrospector(), this.FormattedSpan), changeMap, cancellationToken ); return(rewriter.Transform()); }
private async Task <IFormattingResult> FormatMergedSpanAsync( SyntaxNode node, OptionSet options, IEnumerable <IFormattingRule> rules, IList <TextSpan> spansToFormat, CancellationToken cancellationToken) { var spanToFormat = TextSpan.FromBounds(spansToFormat[0].Start, spansToFormat[spansToFormat.Count - 1].End); var pair = node.ConvertToTokenPair(spanToFormat); if (node.IsInvalidTokenRange(pair.Item1, pair.Item2)) { return(CreateAggregatedFormattingResult(node, SpecializedCollections.EmptyList <AbstractFormattingResult>())); } // more expensive case var result = await FormatAsync(node, options, rules, pair.Item1, pair.Item2, cancellationToken).ConfigureAwait(false); return(CreateAggregatedFormattingResult(node, new List <AbstractFormattingResult>(1) { result }, SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance, spanToFormat))); }
/// <summary> /// Returns true if the passed in node contains an interleaved pp directive. /// /// i.e. The following returns false: /// /// void Foo() { /// #if true /// #endif /// } /// /// #if true /// void Foo() { /// } /// #endif /// /// but these return true: /// /// #if true /// void Foo() { /// #endif /// } /// /// void Foo() { /// #if true /// } /// #endif /// /// #if true /// void Foo() { /// #else /// } /// #endif /// /// i.e. the method returns true if it contains a PP directive that belongs to a grouping /// constructs (like #if/#endif or #region/#endregion), but the grouping construct isn't /// entirely contained within the span of the node. /// </summary> public static bool ContainsInterleavedDirective( this SyntaxNode syntaxNode, CancellationToken cancellationToken) { // Check if this node contains a start or end pp construct whose matching construct is // not contained within this node. If so, this node must be pinned and cannot move. // // Also, keep track of those spans so that if we see #else/#elif we can tell if they // belong to a pp span that is entirely within the node. var ifEndIfSpans = SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance); var span = syntaxNode.Span; foreach (var token in syntaxNode.DescendantTokens()) { if (ContainsInterleavedDirective(span, token, ref ifEndIfSpans, cancellationToken)) { return(true); } } return(false); }
protected SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector> GetFormattingSpans() => _formattingSpans ?? SimpleIntervalTree.Create( new TextSpanIntervalIntrospector(), _formattingResults.Select(r => r.FormattedSpan) );
private static IEnumerable <SimpleIntervalTree <Tuple <int, int, string>, TupleIntrospector <string> > > CreateTrees(IEnumerable <Tuple <int, int, string> > values) { yield return(SimpleIntervalTree.Create(new TupleIntrospector <string>(), values)); }
public void AnalyzeCodeBlock(CodeBlockAnalysisContext context) { if (_analyzer.IsIgnoredCodeBlock(context.CodeBlock)) { return; } var(completed, intervalTree) = _codeBlockIntervals.GetOrAdd(context.CodeBlock.SyntaxTree, _ => (new StrongBox <bool>(false), SimpleIntervalTree.Create(new TextSpanIntervalIntrospector(), Array.Empty <TextSpan>()))); if (completed.Value) { return; } RoslynDebug.AssertNotNull(intervalTree); lock (completed) { if (completed.Value) { return; } if (intervalTree.HasIntervalThatOverlapsWith(context.CodeBlock.FullSpan.Start, context.CodeBlock.FullSpan.End)) { return; } intervalTree.AddIntervalInPlace(context.CodeBlock.FullSpan); } _analyzer.AnalyzeCodeBlock(context); }
protected SimpleIntervalTree <TextSpan> GetFormattingSpans() { return(_formattingSpans ?? SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance, _formattingResults.Select(r => r.FormattedSpan))); }