Exemple #1
0
        /// <summary>
        /// Generate the glyph by the given <paramref name="tag"/>, and add it to the margin.
        /// It should only be called by UI thread because UI elements are manipulated by this method.
        /// </summary>
        public void AddGlyph(InheritanceMarginTag tag, SnapshotSpan span)
        {
            AssertIsForeground();
            var lines = _textView.TextViewLines;

            if (lines.IntersectsBufferSpan(span) && GetStartingLine(lines, span) is IWpfTextViewLine line)
            {
                var glyph = CreateNewGlyph(tag);
                SetTop(line, glyph);
                _glyphDataTree.AddIntervalInPlace(new GlyphData(span, glyph));
                _glyphsContainer.Children.Add(glyph);
            }
        }
        /// <summary>
        /// Try to merge the changes made to <paramref name="newDocument"/> into the tracked changes. If there is any
        /// conflicting change in <paramref name="newDocument"/> with existing changes, then no changes are added.
        /// </summary>
        public async Task TryMergeChangesAsync(Document newDocument, CancellationToken cancellationToken)
        {
            Debug.Assert(newDocument.Id == _oldDocument.Id);

            cancellationToken.ThrowIfCancellationRequested();
            var currentChanges = await _differenceService.GetTextChangesAsync(
                _oldDocument, newDocument, cancellationToken).ConfigureAwait(false);

            if (AllChangesCanBeApplied(_totalChangesIntervalTree, currentChanges))
            {
                foreach (var change in currentChanges)
                {
                    _totalChangesIntervalTree.AddIntervalInPlace(change);
                }
            }
        }
Exemple #3
0
        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());
        }