public async Task<Document> AddImportsAsync(Document document, IEnumerable<TextSpan> spans, OptionSet options, CancellationToken cancellationToken) { options = options ?? document.Project.Solution.Workspace.Options; var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree<TextSpan>(TextSpanIntervalIntrospector.Instance, spans); Func<SyntaxNodeOrToken, bool> isInSpan = (nodeOrToken) => spansTree.GetOverlappingIntervals(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length).Any(); var nodesWithExplicitNamespaces = root.DescendantNodesAndSelf().Where(n => isInSpan(n) && GetExplicitNamespaceSymbol(n, model) != null).ToList(); var namespacesToAdd = new HashSet<INamespaceSymbol>(); namespacesToAdd.AddRange(nodesWithExplicitNamespaces.Select(n => GetExplicitNamespaceSymbol(n, model))); // annotate these nodes so they get simplified later var newRoot = root.ReplaceNodes(nodesWithExplicitNamespaces, (o, r) => r.WithAdditionalAnnotations(Simplifier.Annotation)); var newDoc = document.WithSyntaxRoot(newRoot); var newModel = await newDoc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); newRoot = await this.AddNamespaceImportsAsync(newDoc, newModel, options, namespacesToAdd, cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(newRoot); }
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 }
public AbstractAggregatedFormattingResult( SyntaxNode node, IList<AbstractFormattingResult> formattingResults, SimpleIntervalTree<TextSpan> formattingSpans) { Contract.ThrowIfNull(node); Contract.ThrowIfNull(formattingResults); this.Node = node; _formattingResults = formattingResults; _formattingSpans = formattingSpans; _lazyTextChanges = new CancellableLazy<IList<TextChange>>(CreateTextChanges); _lazyNode = new CancellableLazy<SyntaxNode>(CreateFormattedRoot); }
public TriviaRewriter( SyntaxNode node, SimpleIntervalTree<TextSpan> spanToFormat, Dictionary<ValueTuple<SyntaxToken, SyntaxToken>, TriviaData> map, CancellationToken cancellationToken) { Contract.ThrowIfNull(node); Contract.ThrowIfNull(map); _node = node; _spans = spanToFormat; _cancellationToken = cancellationToken; _trailingTriviaMap = new Dictionary<SyntaxToken, SyntaxTriviaList>(); _leadingTriviaMap = new Dictionary<SyntaxToken, SyntaxTriviaList>(); PreprocessTriviaListMap(map, cancellationToken); }
public async Task <Document> AddImportsAsync( Document document, IEnumerable <TextSpan> spans, OptionSet options, CancellationToken cancellationToken) { options ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree <TextSpan>(TextSpanIntervalIntrospector.Instance, spans); bool isInSpan(SyntaxNodeOrToken nodeOrToken) => spansTree.HasIntervalThatOverlapsWith(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length); var nodesWithExplicitNamespaces = root.DescendantNodesAndSelf().Where(n => isInSpan(n) && GetExplicitNamespaceSymbol(n, model) != null).ToList(); var namespacesToAdd = new HashSet <INamespaceSymbol>(); namespacesToAdd.AddRange(nodesWithExplicitNamespaces.Select( n => GetExplicitNamespaceSymbol(n, model))); var generator = SyntaxGenerator.GetGenerator(document); var imports = namespacesToAdd.Select(ns => generator.NamespaceImportDeclaration(ns.ToDisplayString()).WithAdditionalAnnotations(Simplifier.Annotation)) .ToArray(); // annotate these nodes so they get simplified later var newRoot = root.ReplaceNodes( nodesWithExplicitNamespaces, (o, r) => r.WithAdditionalAnnotations(Simplifier.Annotation)); var placeSystemNamespaceFirst = options.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language); var addImportsService = document.GetLanguageService <IAddImportsService>(); var finalRoot = addImportsService.AddImports( model.Compilation, newRoot, newRoot, imports, placeSystemNamespaceFirst); return(document.WithSyntaxRoot(finalRoot)); }
private static bool AllChangesCanBeApplied( SimpleIntervalTree <TextChange, IntervalIntrospector> cumulativeChanges, ImmutableArray <TextChange> currentChanges, ref TemporaryArray <TextChange> overlappingSpans, ref TemporaryArray <TextChange> intersectingSpans ) { foreach (var change in currentChanges) { overlappingSpans.Clear(); intersectingSpans.Clear(); cumulativeChanges.FillWithIntervalsThatOverlapWith( change.Span.Start, change.Span.Length, ref overlappingSpans ); cumulativeChanges.FillWithIntervalsThatIntersectWith( change.Span.Start, change.Span.Length, ref intersectingSpans ); var value = ChangeCanBeApplied( change, overlappingSpans: in overlappingSpans, intersectingSpans: in intersectingSpans ); if (!value) { return(false); } } // All the changes would merge in fine. We can absorb this. return(true); }
/// <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 override ImmutableArray <Diagnostic> AnalyzeSemanticModel( SemanticModelAnalysisContext context, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?codeBlockIntervalTree ) { var semanticModel = context.SemanticModel; var cancellationToken = context.CancellationToken; var syntaxTree = semanticModel.SyntaxTree; var optionSet = context.Options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); var root = syntaxTree.GetRoot(cancellationToken); var simplifier = new TypeSyntaxSimplifierWalker( this, semanticModel, optionSet, ignoredSpans: codeBlockIntervalTree, cancellationToken ); simplifier.Visit(root); return(simplifier.Diagnostics); }
public async Task<Document> AddImportsAsync( Document document, IEnumerable<TextSpan> spans, OptionSet options, CancellationToken cancellationToken) { options = options ?? await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree<TextSpan>(TextSpanIntervalIntrospector.Instance, spans); Func<SyntaxNodeOrToken, bool> isInSpan = nodeOrToken => spansTree.GetOverlappingIntervals(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length).Any(); var nodesWithExplicitNamespaces = root.DescendantNodesAndSelf().Where(n => isInSpan(n) && GetExplicitNamespaceSymbol(n, model) != null).ToList(); var namespacesToAdd = new HashSet<INamespaceSymbol>(); namespacesToAdd.AddRange(nodesWithExplicitNamespaces.Select( n => GetExplicitNamespaceSymbol(n, model))); var generator = SyntaxGenerator.GetGenerator(document); var imports = namespacesToAdd.Select(ns => generator.NamespaceImportDeclaration(ns.ToDisplayString()).WithAdditionalAnnotations(Simplifier.Annotation)) .ToArray(); // annotate these nodes so they get simplified later var newRoot = root.ReplaceNodes( nodesWithExplicitNamespaces, (o, r) => r.WithAdditionalAnnotations(Simplifier.Annotation)); var placeSystemNamespaceFirst = options.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language); var addImportsService = document.GetLanguageService<IAddImportsService>(); var finalRoot = addImportsService.AddImports( model.Compilation, newRoot, newRoot, imports, placeSystemNamespaceFirst); return document.WithSyntaxRoot(finalRoot); }
protected override IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList<AbstractFormattingResult> results, SimpleIntervalTree<TextSpan> formattingSpans = null) { return new AggregatedFormattingResult(node, results, formattingSpans); }
protected override void AnalyzeSemanticModel(SemanticModelAnalysisContext context, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?codeBlockIntervalTree) { var semanticModel = context.SemanticModel; var cancellationToken = context.CancellationToken; var syntaxTree = semanticModel.SyntaxTree; var optionSet = context.Options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); var root = syntaxTree.GetRoot(cancellationToken); var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, optionSet, ignoredSpans: codeBlockIntervalTree, cancellationToken); simplifier.Visit(root); if (!simplifier.HasDiagnostics) { return; } foreach (var diagnostic in simplifier.Diagnostics) { context.ReportDiagnostic(diagnostic); } }
private async Task <Document> ReduceAsyncInternal( Document document, ImmutableArray <TextSpan> spans, OptionSet optionSet, ImmutableArray <AbstractReducer> reducers, CancellationToken cancellationToken) { // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree <TextSpan>(TextSpanIntervalIntrospector.Instance, spans); bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) => !spansTree.HasIntervalThatOverlapsWith(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // prep namespace imports marked for simplification var removeIfUnusedAnnotation = new SyntaxAnnotation(); var originalRoot = root; root = this.PrepareNamespaceImportsForRemovalIfUnused(document, root, removeIfUnusedAnnotation, isNodeOrTokenOutsideSimplifySpans); var hasImportsToSimplify = root != originalRoot; if (hasImportsToSimplify) { document = document.WithSyntaxRoot(root); semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); } // Get the list of syntax nodes and tokens that need to be reduced. var nodesAndTokensToReduce = this.GetNodesAndTokensToReduce(root, isNodeOrTokenOutsideSimplifySpans); if (nodesAndTokensToReduce.Any()) { if (reducers.IsDefault) { reducers = _reducers; } var reducedNodesMap = new ConcurrentDictionary <SyntaxNode, SyntaxNode>(); var reducedTokensMap = new ConcurrentDictionary <SyntaxToken, SyntaxToken>(); // Reduce all the nodesAndTokensToReduce using the given reducers/rewriters and // store the reduced nodes and/or tokens in the reduced nodes/tokens maps. // Note that this method doesn't update the original syntax tree. await this.ReduceAsync(document, root, nodesAndTokensToReduce, reducers, optionSet, semanticModel, reducedNodesMap, reducedTokensMap, cancellationToken).ConfigureAwait(false); if (reducedNodesMap.Any() || reducedTokensMap.Any()) { // Update the syntax tree with reduced nodes/tokens. root = root.ReplaceSyntax( nodes: reducedNodesMap.Keys, computeReplacementNode: (o, n) => TransformReducedNode(reducedNodesMap[o], n), tokens: reducedTokensMap.Keys, computeReplacementToken: (o, n) => reducedTokensMap[o], trivia: SpecializedCollections.EmptyEnumerable <SyntaxTrivia>(), computeReplacementTrivia: null); document = document.WithSyntaxRoot(root); } } if (hasImportsToSimplify) { // remove any unused namespace imports that were marked for simplification document = await this.RemoveUnusedNamespaceImportsAsync(document, removeIfUnusedAnnotation, cancellationToken).ConfigureAwait(false); } return(document); }
public AggregatedFormattingResult(SyntaxNode node, IList <AbstractFormattingResult> results, SimpleIntervalTree <TextSpan> formattingSpans) : base(node, results, formattingSpans) { }
private ImmutableArray <Diagnostic> AnalyzeSemanticModel(SemanticModelAnalysisContext context, int positionOfFirstReducingNullableDirective, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?codeBlockIntervalTree, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?possibleNullableImpactIntervalTree) { var root = context.SemanticModel.SyntaxTree.GetCompilationUnitRoot(context.CancellationToken); using (var simplifier = new NullableImpactingSpanWalker(context.SemanticModel, positionOfFirstReducingNullableDirective, ignoredSpans: codeBlockIntervalTree, context.CancellationToken)) { simplifier.Visit(root); possibleNullableImpactIntervalTree ??= new SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>(new TextSpanIntervalIntrospector(), values: null); foreach (var interval in simplifier.Spans) { possibleNullableImpactIntervalTree.AddIntervalInPlace(interval); } } using var diagnostics = TemporaryArray <Diagnostic> .Empty; var compilationOptions = ((CSharpCompilationOptions)context.SemanticModel.Compilation.Options).NullableContextOptions; DirectiveTriviaSyntax? previousRetainedDirective = null; NullableContextOptions?retainedOptions = compilationOptions; DirectiveTriviaSyntax?currentOptionsDirective = null; var currentOptions = retainedOptions; for (var directive = root.GetFirstDirective(); directive is not null; directive = directive.GetNextDirective()) { context.CancellationToken.ThrowIfCancellationRequested(); if (directive.IsKind(SyntaxKind.NullableDirectiveTrivia, out NullableDirectiveTriviaSyntax? nullableDirectiveTrivia)) { // Once we reach a new directive, check to see if we can remove the previous directive var removedCurrent = false; if (IsReducing(retainedOptions, currentOptions)) { // We can't have found a reducing directive and not know which directive it was Contract.ThrowIfNull(currentOptionsDirective); if (possibleNullableImpactIntervalTree is null || !possibleNullableImpactIntervalTree.HasIntervalThatOverlapsWith(currentOptionsDirective.Span.End, nullableDirectiveTrivia.SpanStart - currentOptionsDirective.Span.End)) { diagnostics.Add(Diagnostic.Create(Descriptor, currentOptionsDirective.GetLocation())); } } if (!removedCurrent) { previousRetainedDirective = currentOptionsDirective; retainedOptions = currentOptions; } currentOptionsDirective = nullableDirectiveTrivia; currentOptions = CSharpRemoveRedundantNullableDirectiveDiagnosticAnalyzer.GetNullableContextOptions(compilationOptions, currentOptions, nullableDirectiveTrivia); } else if (directive.IsKind(SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElifDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia)) { possibleNullableImpactIntervalTree ??= new SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>(new TextSpanIntervalIntrospector(), values: null); possibleNullableImpactIntervalTree.AddIntervalInPlace(directive.Span); } } // Once we reach the end of the file, check to see if we can remove the last directive if (IsReducing(retainedOptions, currentOptions)) { // We can't have found a reducing directive and not know which directive it was Contract.ThrowIfNull(currentOptionsDirective); if (possibleNullableImpactIntervalTree is null || !possibleNullableImpactIntervalTree.HasIntervalThatOverlapsWith(currentOptionsDirective.Span.End, root.Span.End - currentOptionsDirective.Span.End)) { diagnostics.Add(Diagnostic.Create(Descriptor, currentOptionsDirective.GetLocation())); } } return(diagnostics.ToImmutableAndClear()); }
protected abstract IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList <AbstractFormattingResult> results, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector> formattingSpans = null);
protected override IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList <AbstractFormattingResult> results, SimpleIntervalTree <TextSpan> formattingSpans = null) { return(new AggregatedFormattingResult(node, results, formattingSpans)); }
public async Task <Document> AddImportsAsync( Document document, IEnumerable <TextSpan> spans, Strategy strategy, OptionSet?options, CancellationToken cancellationToken ) { options ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = await document .GetRequiredSyntaxRootAsync(cancellationToken) .ConfigureAwait(false); var addImportsService = document.GetRequiredLanguageService <IAddImportsService>(); var generator = document.GetRequiredLanguageService <SyntaxGenerator>(); // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>( new TextSpanIntervalIntrospector(), spans ); Func <SyntaxNode, bool> overlapsWithSpan = n => spansTree.HasIntervalThatOverlapsWith(n.FullSpan.Start, n.FullSpan.Length); // Only dive deeper into nodes that actually overlap with the span we care about. And also only include // those child nodes that themselves overlap with the span. i.e. if we have: // // Parent // / \ // A [| B C |] D // // We'll dive under the parent because it overlaps with the span. But we only want to include (and dive // into) B and C not A and D. var nodes = root.DescendantNodesAndSelf(overlapsWithSpan).Where(overlapsWithSpan); var placeSystemNamespaceFirst = options.GetOption( GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language ); var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); if (strategy == Strategy.AddImportsFromSymbolAnnotations) { return(await AddImportDirectivesFromSymbolAnnotationsAsync( document, nodes, addImportsService, generator, placeSystemNamespaceFirst, allowInHiddenRegions, cancellationToken ) .ConfigureAwait(false)); } if (strategy == Strategy.AddImportsFromSyntaxes) { return(await AddImportDirectivesFromSyntaxesAsync( document, nodes, addImportsService, generator, placeSystemNamespaceFirst, allowInHiddenRegions, cancellationToken ) .ConfigureAwait(false)); } throw ExceptionUtilities.UnexpectedValue(strategy); }
protected override IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList <AbstractFormattingResult> results, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?formattingSpans = null) => new AggregatedFormattingResult(node, results, formattingSpans);
protected abstract ImmutableArray <Diagnostic> AnalyzeSemanticModel(SemanticModelAnalysisContext context, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?codeBlockIntervalTree);
protected override SyntaxNode Rewriter(Dictionary <ValueTuple <SyntaxToken, SyntaxToken>, TriviaData> changeMap, CancellationToken cancellationToken) { var rewriter = new TriviaRewriter(this.TreeInfo.Root, SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance, this.FormattedSpan), changeMap, cancellationToken); return(rewriter.Transform()); }
protected SimpleIntervalTree <TextSpan> GetFormattingSpans() { return(_formattingSpans ?? SimpleIntervalTree.Create(TextSpanIntervalIntrospector.Instance, _formattingResults.Select(r => r.FormattedSpan))); }
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); }
/// <summary> /// check whether the given span is intersects with the tree /// </summary> public static bool IntersectsWith(this SimpleIntervalTree <TextSpan> tree, TextSpan span) { return(tree.GetIntersectingIntervals(span.Start, span.Length).Any()); }
protected abstract IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList<AbstractFormattingResult> results, SimpleIntervalTree<TextSpan> formattingSpans = null);
protected abstract void AnalyzeSemanticModel(SemanticModelAnalysisContext context, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?codeBlockIntervalTree);
public AggregatedFormattingResult(SyntaxNode node, IList<AbstractFormattingResult> results, SimpleIntervalTree<TextSpan> formattingSpans) : base(node, results, formattingSpans) { }
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 TypeSyntaxSimplifierWalker(CSharpSimplifyTypeNamesDiagnosticAnalyzer analyzer, SemanticModel semanticModel, OptionSet optionSet, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?ignoredSpans, CancellationToken cancellationToken) : base(SyntaxWalkerDepth.StructuredTrivia) { _analyzer = analyzer; _semanticModel = semanticModel; _optionSet = optionSet; _ignoredSpans = ignoredSpans; _cancellationToken = cancellationToken; var root = semanticModel.SyntaxTree.GetRoot(cancellationToken); _aliasedNames = GetAliasedNames(root as CompilationUnitSyntax); }
protected SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector> GetFormattingSpans() => _formattingSpans ?? SimpleIntervalTree.Create( new TextSpanIntervalIntrospector(), _formattingResults.Select(r => r.FormattedSpan) );
/// <summary> /// check whether the given span is intersects with the tree /// </summary> public static bool HasIntervalThatIntersectsWith( this SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector> tree, TextSpan span ) => tree.HasIntervalThatIntersectsWith(span.Start, span.Length);
public async Task <Document> AddImportsAsync( Document document, IEnumerable <TextSpan> spans, Strategy strategy, bool safe, OptionSet?options, CancellationToken cancellationToken) { options ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(model); var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var addImportsService = document.GetRequiredLanguageService <IAddImportsService>(); var generator = document.GetRequiredLanguageService <SyntaxGenerator>(); // Create a simple interval tree for simplification spans. var spansTree = new SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>(new TextSpanIntervalIntrospector(), spans); var nodes = root.DescendantNodesAndSelf().Where(IsInSpan); var(importDirectivesToAdd, namespaceSymbols, context) = strategy switch { Strategy.AddImportsFromSymbolAnnotations => GetImportDirectivesFromAnnotatedNodes(nodes, root, model, addImportsService, generator, cancellationToken), Strategy.AddImportsFromSyntaxes => GetImportDirectivesFromSyntaxes(nodes, ref root, model, addImportsService, generator, cancellationToken), _ => throw new InvalidEnumArgumentException(nameof(strategy), (int)strategy, typeof(Strategy)), }; if (importDirectivesToAdd.Length == 0) { return(document.WithSyntaxRoot(root)); //keep any added simplifier annotations } if (safe) { // Mark the context with an annotation. // This will allow us to find it after we have called MakeSafeToAddNamespaces. var annotation = new SyntaxAnnotation(); RoslynDebug.Assert(context is object); document = document.WithSyntaxRoot(root.ReplaceNode(context, context.WithAdditionalAnnotations(annotation))); root = (await document.GetSyntaxRootAsync().ConfigureAwait(false)) !; model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(model); // Make Safe to add namespaces document = document.WithSyntaxRoot( MakeSafeToAddNamespaces(root, namespaceSymbols, model, document.Project.Solution.Workspace, cancellationToken)); root = (await document.GetSyntaxRootAsync().ConfigureAwait(false)) !; model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(model); // Find the context. It might be null if we have removed the context in the process of complexifying the tree. context = root.DescendantNodesAndSelf().FirstOrDefault(x => x.HasAnnotation(annotation)) ?? root; } var placeSystemNamespaceFirst = options.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language); root = addImportsService.AddImports(model.Compilation, root, context, importDirectivesToAdd, generator, placeSystemNamespaceFirst, cancellationToken); return(document.WithSyntaxRoot(root)); bool IsInSpan(SyntaxNode node) => spansTree.HasIntervalThatOverlapsWith(node.FullSpan.Start, node.FullSpan.Length); }
public TypeSyntaxSimplifierWalker(CSharpSimplifyTypeNamesDiagnosticAnalyzer analyzer, SemanticModel semanticModel, CSharpSimplifierOptions options, SimpleIntervalTree <TextSpan, TextSpanIntervalIntrospector>?ignoredSpans, CancellationToken cancellationToken) : base(SyntaxWalkerDepth.StructuredTrivia) { _analyzer = analyzer; _semanticModel = semanticModel; _options = options; _ignoredSpans = ignoredSpans; _cancellationToken = cancellationToken; var root = semanticModel.SyntaxTree.GetRoot(cancellationToken); _aliasedNames = PooledHashSet <string> .GetInstance(); AddAliasedNames((CompilationUnitSyntax)root); }