private UnprocessedDocumentationCommentFinder(DiagnosticBag diagnostics, TextSpan? filterSpanWithinTree, CancellationToken cancellationToken)
     : base(SyntaxWalkerDepth.Trivia)
 {
     this.diagnostics = diagnostics;
     this.filterSpanWithinTree = filterSpanWithinTree;
     this.cancellationToken = cancellationToken;
 }
 public DiagnosticDataLocation(
     DocumentId documentId = null,
     TextSpan? sourceSpan = null,
     string originalFilePath = null,
     int originalStartLine = 0,
     int originalStartColumn = 0,
     int originalEndLine = 0,
     int originalEndColumn = 0,
     string mappedFilePath = null,
     int mappedStartLine = 0,
     int mappedStartColumn = 0,
     int mappedEndLine = 0,
     int mappedEndColumn = 0)
 {
     DocumentId = documentId;
     SourceSpan = sourceSpan;
     MappedFilePath = mappedFilePath;
     MappedStartLine = mappedStartLine;
     MappedStartColumn = mappedStartColumn;
     MappedEndLine = mappedEndLine;
     MappedEndColumn = mappedEndColumn;
     OriginalFilePath = originalFilePath;
     OriginalStartLine = originalStartLine;
     OriginalStartColumn = originalStartColumn;
     OriginalEndLine = originalEndLine;
     OriginalEndColumn = originalEndColumn;
 }
Exemple #3
0
 public ReplaceAction(string description, SyntaxNode oldNode, SyntaxNode newNode, TextSpan? suggestedSpan = null)
 {
     this.Description = description;
     this.OldNode = oldNode;
     this.NewNode = newNode;
     this.SuggestedSpan = suggestedSpan;
 }
Exemple #4
0
 public void EndParameters(TextSpan context)
 {
     if (request != null)
      {
     currentSpan = null;
     this.Sink.EndParameters(context);
      }
 }
 public DiagnosticAnalyzerDriver(
     Document document,
     TextSpan? span,
     SyntaxNode root,
     DiagnosticIncrementalAnalyzer owner,
     CancellationToken cancellationToken)
     : this(document.Project, owner, cancellationToken)
 {
     _document = document;
     _span = span;
     _root = root;
 }
 public DiagnosticAnalyzerDriver(
     Document document,
     TextSpan? span,
     SyntaxNode root,
     DiagnosticIncrementalAnalyzer owner,
     bool concurrentAnalysis,
     bool reportSuppressedDiagnostics,
     CompilationWithAnalyzers cachedCompilationWithAnalyzersOpt,
     CancellationToken cancellationToken)
     : this(document.Project, owner, concurrentAnalysis, reportSuppressedDiagnostics, cachedCompilationWithAnalyzersOpt, cancellationToken)
 {
     _document = document;
     _span = span;
     _root = root;
 }
        private ClsComplianceChecker(
            CSharpCompilation compilation,
            SyntaxTree filterTree,
            TextSpan? filterSpanWithinTree,
            ConcurrentQueue<Diagnostic> diagnostics,
            CancellationToken cancellationToken)
        {
            _compilation = compilation;
            _filterTree = filterTree;
            _filterSpanWithinTree = filterSpanWithinTree;
            _diagnostics = diagnostics;
            _cancellationToken = cancellationToken;

            _declaredOrInheritedCompliance = new ConcurrentDictionary<Symbol, Compliance>();
        }
 // internal for testing purposes
 internal DiagnosticAnalyzerDriver(
     Document document,
     TextSpan? span,
     SyntaxNode root,
     ISyntaxNodeAnalyzerService syntaxNodeAnalyzerService,
     CancellationToken cancellationToken,
     bool testOnly_DonotCatchAnalyzerExceptions = false)
 {
     _document = document;
     _span = span;
     _root = root;
     _project = document.Project;
     _syntaxNodeAnalyzerService = syntaxNodeAnalyzerService;
     _cancellationToken = cancellationToken;
     _descendantExecutableNodesMap = new Dictionary<SyntaxNode, ImmutableArray<SyntaxNode>>();
     _syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
     _generatedCodeService = document.Project.Solution.Workspace.Services.GetService<IGeneratedCodeRecognitionService>();
     _analyzerDriverService = document.Project.LanguageServices.GetService<IAnalyzerDriverService>();
     _analyzerOptions = new WorkspaceAnalyzerOptions(_project.AnalyzerOptions, _project.Solution.Workspace);
     _testOnly_DonotCatchAnalyzerExceptions = testOnly_DonotCatchAnalyzerExceptions;
 }
        private DocumentationCommentCompiler(
            string assemblyName,
            CSharpCompilation compilation,
            TextWriter writer,
            SyntaxTree filterTree,
            TextSpan? filterSpanWithinTree,
            bool processIncludes,
            bool isForSingleSymbol,
            DiagnosticBag diagnostics,
            CancellationToken cancellationToken)
        {
            _assemblyName = assemblyName;

            _compilation = compilation;
            _writer = writer;
            _filterTree = filterTree;
            _filterSpanWithinTree = filterSpanWithinTree;
            _processIncludes = processIncludes;
            _isForSingleSymbol = isForSingleSymbol;
            _diagnostics = diagnostics;
            _cancellationToken = cancellationToken;
        }
Exemple #10
0
 public void SetContext(ParseRequest parseRequest)
 {
     this.request = parseRequest;
        this.currentSpan = null;
     braces = new List<TextSpan[]>();
 }
Exemple #11
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="compilerName">Compiler name (<see cref="PredefinedCompilerNames"/>) or null</param>
 /// <param name="decompilerSettingsVersion">Decompiler settings version number. This version number should get incremented when the settings change.</param>
 /// <param name="stateMachineKind">State machine kind</param>
 /// <param name="method">Method</param>
 /// <param name="kickoffMethod">Kickoff method or null</param>
 /// <param name="parameters">Parameters or null</param>
 /// <param name="statements">Statements</param>
 /// <param name="scope">Root scope</param>
 /// <param name="methodSpan">Method span or null to calculate it from <paramref name="statements"/></param>
 /// <param name="asyncMethodDebugInfo">Async info or null</param>
 public MethodDebugInfo(string compilerName, int decompilerSettingsVersion, StateMachineKind stateMachineKind, MethodDef method, MethodDef kickoffMethod, SourceParameter[] parameters, SourceStatement[] statements, MethodDebugScope scope, TextSpan?methodSpan, AsyncMethodDebugInfo asyncMethodDebugInfo)
 {
     if (statements == null)
     {
         throw new ArgumentNullException(nameof(statements));
     }
     CompilerName  = compilerName;
     Method        = method ?? throw new ArgumentNullException(nameof(method));
     KickoffMethod = kickoffMethod;
     Parameters    = parameters ?? Array.Empty <SourceParameter>();
     if (statements.Length > 1)
     {
         Array.Sort(statements, SourceStatement.SpanStartComparer);
     }
     DecompilerSettingsVersion = decompilerSettingsVersion;
     Statements = statements;
     Scope      = scope ?? throw new ArgumentNullException(nameof(scope));
     Span       = methodSpan ?? CalculateMethodSpan(statements) ?? new TextSpan(0, 0);
     AsyncInfo  = asyncMethodDebugInfo;
 }
        protected static Tuple<Document[], bool, TextSpan?[]> VerifyAndGetDocumentsAndSpan(string[] sources, string language)
        {
            Assert.True(language == LanguageNames.CSharp || language == LanguageNames.VisualBasic, "Unsupported language");

            var spans = new TextSpan?[sources.Length];
            bool useSpans = false;

            for (int i = 0; i < sources.Length; i++)
            {
                string fileName = language == LanguageNames.CSharp ? "Test" + i + ".cs" : "Test" + i + ".vb";

                string source;
                int? pos;
                TextSpan? span;
                MarkupTestFile.GetPositionAndSpan(sources[i], out source, out pos, out span);

                sources[i] = source;
                spans[i] = span;

                if (span != null)
                {
                    useSpans = true;
                }
            }

            var project = CreateProject(sources, language);
            var documents = project.Documents.ToArray();
            Assert.Equal(sources.Length, documents.Length);

            return Tuple.Create(documents, useSpans, spans);
        }
Exemple #13
0
            /// <summary>
            /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) by calculating them
            /// </summary>
            public async Task <IEnumerable <DiagnosticData> > ComputeDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan?spanOpt, CancellationToken cancellationToken)
            {
                var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer;

                if (documentAnalyzer != null)
                {
                    var diagnostics = await ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(document, documentAnalyzer, kind, analyzerDriverOpt?.Compilation, cancellationToken).ConfigureAwait(false);

                    return(ConvertToLocalDiagnostics(document, diagnostics));
                }

                var documentDiagnostics = await ComputeDiagnosticAnalyzerDiagnosticsAsync(analyzerDriverOpt, document, analyzer, kind, spanOpt, cancellationToken).ConfigureAwait(false);

                return(ConvertToLocalDiagnostics(document, documentDiagnostics));
            }
        private async Task <SuppressionTargetInfo> GetSuppressionTargetInfoAsync(Document document, TextSpan span, CancellationToken cancellationToken)
        {
            var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            if (syntaxTree.GetLineVisibility(span.Start, cancellationToken) == LineVisibility.Hidden)
            {
                return(null);
            }

            // Find the start token to attach leading pragma disable warning directive.
            var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var lines       = syntaxTree.GetText(cancellationToken).Lines;
            var indexOfLine = lines.IndexOf(span.Start);
            var lineAtPos   = lines[indexOfLine];
            var startToken  = root.FindToken(lineAtPos.Start);

            startToken = GetAdjustedTokenForPragmaDisable(startToken, root, lines, indexOfLine);

            // Find the end token to attach pragma restore warning directive.
            var spanEnd = Math.Max(startToken.Span.End, span.End);

            indexOfLine = lines.IndexOf(spanEnd);
            lineAtPos   = lines[indexOfLine];
            var endToken = root.FindToken(lineAtPos.End);

            endToken = GetAdjustedTokenForPragmaRestore(endToken, root, lines, indexOfLine);

            var nodeWithTokens = GetNodeWithTokens(startToken, endToken, root);

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            ISymbol targetSymbol     = null;
            var     targetMemberNode = syntaxFacts.GetContainingMemberDeclaration(root, nodeWithTokens.SpanStart);

            if (targetMemberNode != null)
            {
                targetSymbol = semanticModel.GetDeclaredSymbol(targetMemberNode, cancellationToken);

                if (targetSymbol == null)
                {
                    var analyzerDriverService = document.GetLanguageService <IAnalyzerDriverService>();

                    // targetMemberNode could be a declaration node with multiple decls (e.g. field declaration defining multiple variables).
                    // Let us compute all the declarations intersecting the span.
                    var declsBuilder = ArrayBuilder <DeclarationInfo> .GetInstance();

                    analyzerDriverService.ComputeDeclarationsInSpan(semanticModel, span, true, declsBuilder, cancellationToken);
                    var decls = declsBuilder.ToImmutableAndFree();

                    if (!decls.IsEmpty)
                    {
                        var containedDecls = decls.Where(d => span.Contains(d.DeclaredNode.Span));
                        if (containedDecls.Count() == 1)
                        {
                            // Single containing declaration, use this symbol.
                            var decl = containedDecls.Single();
                            targetSymbol = decl.DeclaredSymbol;
                        }
                        else
                        {
                            // Otherwise, use the most enclosing declaration.
                            TextSpan?minContainingSpan = null;
                            foreach (var decl in decls)
                            {
                                var declSpan = decl.DeclaredNode.Span;
                                if (declSpan.Contains(span) &&
                                    (!minContainingSpan.HasValue || minContainingSpan.Value.Contains(declSpan)))
                                {
                                    minContainingSpan = declSpan;
                                    targetSymbol      = decl.DeclaredSymbol;
                                }
                            }
                        }
                    }
                }
            }

            if (targetSymbol == null)
            {
                // Outside of a member declaration, suppress diagnostic for the entire assembly.
                targetSymbol = semanticModel.Compilation.Assembly;
            }

            return(new SuppressionTargetInfo()
            {
                TargetSymbol = targetSymbol, NodeWithTokens = nodeWithTokens, StartToken = startToken, EndToken = endToken, TargetMemberNode = targetMemberNode
            });
        }
        async Task <ImmutableArray <TextChange> > IFormattingInteractionService.GetFormattingChangesAsync(Document document, TextSpan?textSpan, DocumentOptionSet?documentOptions, CancellationToken cancellationToken)
        {
            var changes = await GetFormattingChangesAsync(document, textSpan, documentOptions, cancellationToken).ConfigureAwait(false);

            return(changes?.ToImmutableArray() ?? ImmutableArray <TextChange> .Empty);
        }
Exemple #16
0
        internal static bool TryGetAttributeInfo(
            RazorSyntaxNode attributeLeafOwner,
            out TextSpan?prefixLocation,
            out string attributeName,
            out TextSpan attributeNameLocation,
            out string parameterName,
            out TextSpan parameterLocation)
        {
            var attribute = attributeLeafOwner.Parent;

            // The null check on the `NamePrefix` field is required for cases like:
            // `<svg xml:base=""x| ></svg>` where there's no `NamePrefix` available.
            switch (attribute)
            {
            case MarkupMinimizedAttributeBlockSyntax minimizedMarkupAttribute:
                prefixLocation = minimizedMarkupAttribute.NamePrefix?.Span;
                TryExtractIncompleteDirectiveAttribute(
                    minimizedMarkupAttribute.Name.GetContent(),
                    minimizedMarkupAttribute.Name.Span,
                    out attributeName,
                    out attributeNameLocation,
                    out parameterName,
                    out parameterLocation);

                return(true);

            case MarkupAttributeBlockSyntax markupAttribute:
                prefixLocation = markupAttribute.NamePrefix?.Span;
                TryExtractIncompleteDirectiveAttribute(
                    markupAttribute.Name.GetContent(),
                    markupAttribute.Name.Span,
                    out attributeName,
                    out attributeNameLocation,
                    out parameterName,
                    out parameterLocation);
                return(true);

            case MarkupMinimizedTagHelperAttributeSyntax minimizedTagHelperAttribute:
                prefixLocation = minimizedTagHelperAttribute.NamePrefix?.Span;
                TryExtractIncompleteDirectiveAttribute(
                    minimizedTagHelperAttribute.Name.GetContent(),
                    minimizedTagHelperAttribute.Name.Span,
                    out attributeName,
                    out attributeNameLocation,
                    out parameterName,
                    out parameterLocation);
                return(true);

            case MarkupTagHelperAttributeSyntax tagHelperAttribute:
                prefixLocation = tagHelperAttribute.NamePrefix?.Span;
                TryExtractIncompleteDirectiveAttribute(
                    tagHelperAttribute.Name.GetContent(),
                    tagHelperAttribute.Name.Span,
                    out attributeName,
                    out attributeNameLocation,
                    out parameterName,
                    out parameterLocation);
                return(true);

            case MarkupTagHelperDirectiveAttributeSyntax directiveAttribute:
            {
                var attributeNameNode            = directiveAttribute.Name;
                var directiveAttributeTransition = directiveAttribute.Transition;
                var nameStart = directiveAttributeTransition?.SpanStart ?? attributeNameNode.SpanStart;
                var nameEnd   = attributeNameNode?.Span.End ?? directiveAttributeTransition.Span.End;
                prefixLocation        = directiveAttribute.NamePrefix?.Span;
                attributeName         = string.Concat(directiveAttributeTransition?.GetContent(), attributeNameNode?.GetContent());
                attributeNameLocation = new TextSpan(nameStart, nameEnd - nameStart);
                parameterName         = directiveAttribute.ParameterName?.GetContent();
                parameterLocation     = directiveAttribute.ParameterName?.Span ?? default;
                return(true);
            }

            case MarkupMinimizedTagHelperDirectiveAttributeSyntax minimizedDirectiveAttribute:
            {
                var attributeNameNode            = minimizedDirectiveAttribute.Name;
                var directiveAttributeTransition = minimizedDirectiveAttribute.Transition;
                var nameStart = directiveAttributeTransition?.SpanStart ?? attributeNameNode.SpanStart;
                var nameEnd   = attributeNameNode?.Span.End ?? directiveAttributeTransition.Span.End;
                prefixLocation        = minimizedDirectiveAttribute.NamePrefix?.Span;
                attributeName         = string.Concat(directiveAttributeTransition?.GetContent(), attributeNameNode?.GetContent());
                attributeNameLocation = new TextSpan(nameStart, nameEnd - nameStart);
                parameterName         = minimizedDirectiveAttribute.ParameterName?.GetContent();
                parameterLocation     = minimizedDirectiveAttribute.ParameterName?.Span ?? default;
                return(true);
            }
            }

            prefixLocation        = default;
            attributeName         = null;
            attributeNameLocation = default;
            parameterName         = null;
            parameterLocation     = default;
            return(false);
        }
Exemple #17
0
 private static bool IsBetter(Microsoft.CodeAnalysis.SignatureHelp.SignatureHelpItems bestItems, TextSpan?currentTextSpan)
 {
     return(bestItems == null || currentTextSpan?.Start > bestItems.ApplicableSpan.Start);
 }
Exemple #18
0
 private static string GetSemanticLogMessage(Document document, TextSpan?span, DiagnosticAnalyzer analyzer)
 {
     return(string.Format("semantic: {0}, {1}, {2}", document.FilePath ?? document.Name, span.HasValue ? span.Value.ToString() : "Full", analyzer.ToString()));
 }
Exemple #19
0
 /// <summary>
 /// Get all the errors within the syntax tree associated with this object. Includes errors
 /// involving compiling method bodies or initializers, in addition to the errors returned by
 /// GetDeclarationDiagnostics.
 /// </summary>
 /// <param name="span">Optional span within the syntax tree for which to get diagnostics.
 /// If no argument is specified, then diagnostics for the entire tree are returned.</param>
 /// <param name="cancellationToken">A cancellation token that can be used to cancel the
 /// process of obtaining the diagnostics.</param>
 /// <remarks>
 /// Because this method must semantically bind all method bodies and initializers to check
 /// for diagnostics, it may take a significant amount of time. Unlike
 /// GetDeclarationDiagnostics, diagnostics for method bodies and initializers are not
 /// cached, any semantic information used to obtain the diagnostics is discarded.
 /// </remarks>
 public abstract ImmutableArray <Diagnostic> GetDiagnostics(TextSpan?span = null, CancellationToken cancellationToken = default(CancellationToken));
Exemple #20
0
        public async Task <IList <TextChange> > GetFormattingChangesAsync(Document document, TextSpan?textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            return(Formatter.GetFormattedTextChanges(root,
                                                     SpecializedCollections.SingletonEnumerable(formattingSpan),
                                                     document.Project.Solution.Workspace, options, cancellationToken));
        }
Exemple #21
0
 private Action <Diagnostic> GetAddDiagnostic(SyntaxTree tree, TextSpan?span, DiagnosticAnalyzer analyzer, bool isSyntaxDiagnostic)
 {
     return(GetAddDiagnostic(tree, span, analyzer, false, _addDiagnostic, _addLocalDiagnosticOpt, _addNonLocalDiagnosticOpt));
 }
Exemple #22
0
        public DiagnosticData(
            string id,
            string category,
            string message,
            string enuMessageForBingSearch,
            DiagnosticSeverity severity,
            DiagnosticSeverity defaultSeverity,
            bool isEnabledByDefault,
            int warningLevel,
            IReadOnlyList <string> customTags,
            ImmutableDictionary <string, string> properties,
            Workspace workspace,
            ProjectId projectId,
            DocumentId documentId   = null,
            TextSpan?span           = null,
            string mappedFilePath   = null,
            int mappedStartLine     = 0,
            int mappedStartColumn   = 0,
            int mappedEndLine       = 0,
            int mappedEndColumn     = 0,
            string originalFilePath = null,
            int originalStartLine   = 0,
            int originalStartColumn = 0,
            int originalEndLine     = 0,
            int originalEndColumn   = 0,
            string title            = null,
            string description      = null,
            string helpLink         = null)
        {
            this.Id       = id;
            this.Category = category;
            this.Message  = message;
            this.ENUMessageForBingSearch = enuMessageForBingSearch;

            this.Severity           = severity;
            this.DefaultSeverity    = defaultSeverity;
            this.IsEnabledByDefault = isEnabledByDefault;
            this.WarningLevel       = warningLevel;
            this.CustomTags         = customTags;
            this.Properties         = properties;

            this.Workspace  = workspace;
            this.ProjectId  = projectId;
            this.DocumentId = documentId;

            this.MappedStartLine   = mappedStartLine;
            this.MappedStartColumn = mappedStartColumn;
            this.MappedEndLine     = mappedEndLine;
            this.MappedEndColumn   = mappedEndColumn;
            this.MappedFilePath    = mappedFilePath;

            this.OriginalStartLine   = originalStartLine;
            this.OriginalStartColumn = originalStartColumn;
            this.OriginalEndLine     = originalEndLine;
            this.OriginalEndColumn   = originalEndColumn;
            this.OriginalFilePath    = originalFilePath;

            _textSpan = span;

            this.Title       = title;
            this.Description = description;
            this.HelpLink    = helpLink;
        }
Exemple #23
0
 internal ExpressionChain(BinaryExpressionSyntax binaryExpression, TextSpan?span = null)
 {
     BinaryExpression = binaryExpression;
     Span             = span;
 }
Exemple #24
0
            private IEnumerable <DiagnosticData> ConvertToLocalDiagnosticsWithCompilation(Document targetDocument, IEnumerable <Diagnostic> diagnostics, TextSpan?span = null)
            {
                var project = targetDocument.Project;

                Contract.ThrowIfFalse(project.SupportsCompilation);

                foreach (var diagnostic in diagnostics)
                {
                    var document = project.GetDocument(diagnostic.Location.SourceTree);
                    if (document == null || document != targetDocument)
                    {
                        continue;
                    }

                    if (span.HasValue && !span.Value.Contains(diagnostic.Location.SourceSpan))
                    {
                        continue;
                    }

                    yield return(DiagnosticData.Create(document, diagnostic));
                }
            }
Exemple #25
0
 private static IEnumerable <DiagnosticData> GetDiagnosticData(Document document, SyntaxTree tree, TextSpan?span, IEnumerable <Diagnostic> diagnostics)
 {
     return(diagnostics != null?diagnostics.Where(dx => ShouldIncludeDiagnostic(dx, tree, span)).Select(d => DiagnosticData.Create(document, d)) : null);
 }
Exemple #26
0
            internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, LinkedFileMergeSessionResult mergeResult, IEnumerable <Document> documents, CancellationToken cancellationToken)
            {
                AssertIsForeground();

                if (!AreAllReferenceSpansMappable())
                {
                    // don't dynamically update the reference spans for documents with unmappable projections
                    return;
                }

                using (new SelectionTracking(this))
                {
                    // 1. Undo any previous edits and update the buffer to resulting document after conflict resolution
                    _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false);

                    var newDocument      = mergeResult.MergedSolution.GetDocument(documents.First().Id);
                    var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id);

                    var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken);

                    // TODO: why does the following line hang when uncommented?
                    // newDocument.GetTextChangesAsync(this.baseDocuments.Single(d => d.Id == newDocument.Id), cancellationToken).WaitAndGetResult(cancellationToken).Reverse();

                    _session.UndoManager.CreateConflictResolutionUndoTransaction(_subjectBuffer, () =>
                    {
                        using (var edit = _subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, null, s_propagateSpansEditTag))
                        {
                            foreach (var change in changes)
                            {
                                edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
                            }

                            edit.ApplyAndLogExceptions();
                        }
                    });

                    // 2. We want to update referenceSpanToLinkedRenameSpanMap where spans were affected by conflict resolution.
                    // We also need to add the remaining document edits to conflictResolutionRenameTrackingSpans
                    // so they get classified/tagged correctly in the editor.
                    _conflictResolutionRenameTrackingSpans.Clear();

                    var documentReplacements = documents
                                               .Select(document => (document, conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None).ToImmutableArray()))
                                               .ToImmutableArray();

                    var firstDocumentReplacements     = documentReplacements.FirstOrDefault(d => !d.Item2.IsEmpty);
                    var bufferContainsLinkedDocuments = documentReplacements.Length > 1 && firstDocumentReplacements.document != null;
                    var linkedDocumentsMightConflict  = bufferContainsLinkedDocuments;
                    if (linkedDocumentsMightConflict)
                    {
                        // When changes are made and linked documents are involved, some of the linked documents may
                        // have changes that differ from others. When these changes conflict (both differ and overlap),
                        // the inline rename UI reveals the conflicts. However, the merge process for finding these
                        // conflicts is slow, so we want to avoid it when possible. This code block attempts to set
                        // linkedDocumentsMightConflict back to false, eliminating the need to merge the changes as part
                        // of the conflict detection process. Currently we only special case one scenario: ignoring
                        // documents that have no changes at all, we check if all linked documents have exactly the same
                        // set of changes.

                        // 1. Check if all documents have the same replacement spans (or no replacements)
                        var spansMatch = true;
                        foreach (var(document, replacements) in documentReplacements)
                        {
                            if (document == firstDocumentReplacements.document || replacements.IsEmpty)
                            {
                                continue;
                            }

                            if (replacements.Length != firstDocumentReplacements.Item2.Length)
                            {
                                spansMatch = false;
                                break;
                            }

                            for (var i = 0; i < replacements.Length; i++)
                            {
                                if (!replacements[i].Equals(firstDocumentReplacements.Item2[i]))
                                {
                                    spansMatch = false;
                                    break;
                                }
                            }

                            if (!spansMatch)
                            {
                                break;
                            }
                        }

                        // 2. If spans match, check content
                        if (spansMatch)
                        {
                            linkedDocumentsMightConflict = false;

                            // Only need to check the new span's content
                            var firstDocumentNewText     = conflictResolution.NewSolution.GetDocument(firstDocumentReplacements.document.Id).GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                            var firstDocumentNewSpanText = firstDocumentReplacements.Item2.SelectAsArray(replacement => firstDocumentNewText.ToString(replacement.NewSpan));
                            foreach (var(document, replacements) in documentReplacements)
                            {
                                if (document == firstDocumentReplacements.document || replacements.IsEmpty)
                                {
                                    continue;
                                }

                                var documentNewText = conflictResolution.NewSolution.GetDocument(document.Id).GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                                for (var i = 0; i < replacements.Length; i++)
                                {
                                    if (documentNewText.ToString(replacements[i].NewSpan) != firstDocumentNewSpanText[i])
                                    {
                                        // Have to use the slower merge process
                                        linkedDocumentsMightConflict = true;
                                        break;
                                    }
                                }

                                if (linkedDocumentsMightConflict)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    foreach (var document in documents)
                    {
                        var relevantReplacements = conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None);
                        if (!relevantReplacements.Any())
                        {
                            continue;
                        }

                        var mergedReplacements = linkedDocumentsMightConflict
                            ? GetMergedReplacementInfos(
                            relevantReplacements,
                            conflictResolution.NewSolution.GetDocument(document.Id),
                            mergeResult.MergedSolution.GetDocument(document.Id),
                            cancellationToken)
                            : relevantReplacements;

                        // Show merge conflicts comments as unresolvable conflicts, and do not
                        // show any other rename-related spans that overlap a merge conflict comment.
                        var mergeConflictComments = mergeResult.MergeConflictCommentSpans.ContainsKey(document.Id)
                            ? mergeResult.MergeConflictCommentSpans[document.Id]
                            : SpecializedCollections.EmptyEnumerable <TextSpan>();

                        foreach (var conflict in mergeConflictComments)
                        {
                            // TODO: Add these to the unresolvable conflict counts in the dashboard

                            _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                                                           _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(conflict.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                                                           RenameSpanKind.UnresolvedConflict));
                        }

                        foreach (var replacement in mergedReplacements)
                        {
                            var kind = GetRenameSpanKind(replacement.Kind);

                            if (_referenceSpanToLinkedRenameSpanMap.ContainsKey(replacement.OriginalSpan) && kind != RenameSpanKind.Complexified)
                            {
                                var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan(
                                    new InlineRenameLocation(newDocument, replacement.NewSpan), GetWithoutAttributeSuffix(_session.ReplacementText, document.GetLanguageService <LanguageServices.ISyntaxFactsService>().IsCaseSensitive), cancellationToken);
                                if (linkedRenameSpan.HasValue)
                                {
                                    if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                    {
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                            _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(
                                                linkedRenameSpan.Value.ToSpan(),
                                                SpanTrackingMode.EdgeInclusive,
                                                TrackingFidelityMode.Forward),
                                            kind);
                                    }
                                }
                                else
                                {
                                    // We might not have a renameable span if an alias conflict completely changed the text
                                    _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan].TrackingSpan,
                                        RenameSpanKind.None);

                                    if (_activeSpan.HasValue && _activeSpan.Value.IntersectsWith(replacement.OriginalSpan))
                                    {
                                        _activeSpan = null;
                                    }
                                }
                            }
                            else
                            {
                                if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                {
                                    _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                                                                   _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(replacement.NewSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                                                                   kind));
                                }
                            }
                        }

                        if (!linkedDocumentsMightConflict)
                        {
                            break;
                        }
                    }

                    UpdateReadOnlyRegions();

                    // 3. Reset the undo state and notify the taggers.
                    this.ApplyReplacementText(updateSelection: false);
                    RaiseSpansChanged();
                }
            }
Exemple #27
0
        private static bool ShouldIncludeDiagnostic(Diagnostic diagnostic, SyntaxTree tree, TextSpan?span)
        {
            if (diagnostic == null)
            {
                return(false);
            }

            if (diagnostic.Location == null || diagnostic.Location == Location.None)
            {
                return(false);
            }

            if (diagnostic.Location.SourceTree != tree)
            {
                return(false);
            }

            if (span == null)
            {
                return(true);
            }

            return(span.Value.Contains(diagnostic.Location.SourceSpan));
        }
Exemple #28
0
            protected IEnumerable <SuggestedActionSet> ConvertToSuggestedActionSets(ReferenceCountedDisposable <State> state, TextSpan?selection, ImmutableArray <UnifiedSuggestedActionSet> fixes, ImmutableArray <UnifiedSuggestedActionSet> refactorings)
            {
                var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection);

                return(filteredSets.SelectAsArray(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull());
            }
Exemple #29
0
            static async Task <TCompletionItem> CreateCompletionItemAsync <TCompletionItem>(
                LSP.CompletionParams request,
                Document document,
                CompletionItem item,
                CompletionResolveData?completionResolveData,
                bool supportsVSExtensions,
                Dictionary <ImmutableArray <CharacterSetModificationRule>, string[]> commitCharacterRulesCache,
                CompletionService completionService,
                string?clientName,
                bool returnTextEdits,
                bool snippetsSupported,
                StringBuilder stringBuilder,
                SourceText?documentText,
                TextSpan?defaultSpan,
                LSP.Range?defaultRange,
                CancellationToken cancellationToken) where TCompletionItem : LSP.CompletionItem, new()
            {
                // Generate display text
                stringBuilder.Append(item.DisplayTextPrefix);
                stringBuilder.Append(item.DisplayText);
                stringBuilder.Append(item.DisplayTextSuffix);
                var completeDisplayText = stringBuilder.ToString();

                stringBuilder.Clear();

                var completionItem = new TCompletionItem
                {
                    Label      = completeDisplayText,
                    SortText   = item.SortText,
                    FilterText = item.FilterText,
                    Kind       = GetCompletionKind(item.Tags),
                    Data       = completionResolveData,
                    Preselect  = ShouldItemBePreselected(item),
                };

                // Complex text edits (e.g. override and partial method completions) are always populated in the
                // resolve handler, so we leave both TextEdit and InsertText unpopulated in these cases.
                if (item.IsComplexTextEdit)
                {
                    // Razor C# is currently the only language client that supports LSP.InsertTextFormat.Snippet.
                    // We can enable it for regular C# once LSP is used for local completion.
                    if (snippetsSupported)
                    {
                        completionItem.InsertTextFormat = LSP.InsertTextFormat.Snippet;
                    }
                }
                // If the feature flag is on, always return a TextEdit.
                else if (returnTextEdits)
                {
                    var textEdit = await GenerateTextEdit(
                        document, item, completionService, documentText, defaultSpan, defaultRange, cancellationToken).ConfigureAwait(false);

                    completionItem.TextEdit = textEdit;
                }
                // If the feature flag is off, return an InsertText.
                else
                {
                    completionItem.InsertText = SymbolCompletionItem.TryGetInsertionText(item, out var insertionText) ? insertionText : completeDisplayText;
                }

                var commitCharacters = GetCommitCharacters(item, commitCharacterRulesCache, supportsVSExtensions);

                if (commitCharacters != null)
                {
                    completionItem.CommitCharacters = commitCharacters;
                }

                return(completionItem);
Exemple #30
0
 protected virtual Task <IList <TextChange> > GetFormattingChangesAsync(IEditorFormattingService formattingService, Document document, TextSpan?textSpan, CancellationToken cancellationToken)
 => formattingService.GetFormattingChangesAsync(document, textSpan, cancellationToken);
            internal void SetReferenceSpans(IEnumerable<TextSpan> spans)
            {
                AssertIsForeground();

                if (spans.SetEquals(_referenceSpanToLinkedRenameSpanMap.Keys))
                {
                    return;
                }

                using (new SelectionTracking(this))
                {
                    // Revert any previous edits in case we're removing spans.  Undo conflict resolution as well to avoid 
                    // handling the various edge cases where a tracking span might not map to the right span in the current snapshot
                    _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false);

                    _referenceSpanToLinkedRenameSpanMap.Clear();
                    foreach (var span in spans)
                    {
                        var renameableSpan = _session._renameInfo.GetReferenceEditSpan(
                            new InlineRenameLocation(_baseDocuments.First(), span), CancellationToken.None);
                        var trackingSpan = new RenameTrackingSpan(
                                _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(renameableSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                RenameSpanKind.Reference);

                        _referenceSpanToLinkedRenameSpanMap[span] = trackingSpan;
                    }

                    _activeSpan = _activeSpan.HasValue && spans.Contains(_activeSpan.Value)
                        ? _activeSpan
                        : spans.FirstOrNullable();

                    UpdateReadOnlyRegions();
                    this.ApplyReplacementText(updateSelection: false);
                }

                RaiseSpansChanged();
            }
Exemple #32
0
            public IEnumerable <DiagnosticData> ConvertToLocalDiagnostics(Document targetDocument, IEnumerable <Diagnostic> diagnostics, TextSpan?span = null)
            {
                var project = targetDocument.Project;

                if (project.SupportsCompilation)
                {
                    return(ConvertToLocalDiagnosticsWithCompilation(targetDocument, diagnostics, span));
                }

                return(ConvertToLocalDiagnosticsWithoutCompilation(targetDocument, diagnostics, span));
            }
            internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, IEnumerable<Document> documents, CancellationToken cancellationToken)
            {
                AssertIsForeground();

                using (new SelectionTracking(this))
                {
                    // 1. Undo any previous edits and update the buffer to resulting document after conflict resolution
                    _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false);

                    var preMergeSolution = _session._baseSolution;
                    var postMergeSolution = conflictResolution.NewSolution;

                    var diffMergingSession = new LinkedFileDiffMergingSession(preMergeSolution, postMergeSolution, postMergeSolution.GetChanges(preMergeSolution), logSessionInfo: true);
                    var mergeResult = diffMergingSession.MergeDiffsAsync(mergeConflictHandler: null, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);

                    var newDocument = mergeResult.MergedSolution.GetDocument(documents.First().Id);
                    var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id);

                    var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken);

                    // TODO: why does the following line hang when uncommented?
                    // newDocument.GetTextChangesAsync(this.baseDocuments.Single(d => d.Id == newDocument.Id), cancellationToken).WaitAndGetResult(cancellationToken).Reverse();

                    _session.UndoManager.CreateConflictResolutionUndoTransaction(_subjectBuffer, () =>
                    {
                        using (var edit = _subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, null, s_propagateSpansEditTag))
                        {
                            foreach (var change in changes)
                            {
                                edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
                            }

                            edit.Apply();
                        }
                    });

                    // 2. We want to update referenceSpanToLinkedRenameSpanMap where spans were affected by conflict resolution.
                    // We also need to add the remaining document edits to conflictResolutionRenameTrackingSpans
                    // so they get classified/tagged correctly in the editor.
                    _conflictResolutionRenameTrackingSpans.Clear();

                    foreach (var document in documents)
                    {
                        var relevantReplacements = conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None);
                        if (!relevantReplacements.Any())
                        {
                            continue;
                        }

                        var bufferContainsLinkedDocuments = documents.Skip(1).Any();
                        var mergedReplacements = bufferContainsLinkedDocuments
                            ? GetMergedReplacementInfos(
                                relevantReplacements,
                                conflictResolution.NewSolution.GetDocument(document.Id),
                                mergeResult.MergedSolution.GetDocument(document.Id),
                                cancellationToken)
                            : relevantReplacements;

                        // Show merge conflicts comments as unresolvable conflicts, and do not 
                        // show any other rename-related spans that overlap a merge conflict comment.
                        var mergeConflictComments = mergeResult.MergeConflictCommentSpans.ContainsKey(document.Id)
                            ? mergeResult.MergeConflictCommentSpans[document.Id]
                            : SpecializedCollections.EmptyEnumerable<TextSpan>();

                        foreach (var conflict in mergeConflictComments)
                        {
                            // TODO: Add these to the unresolvable conflict counts in the dashboard

                            _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(conflict.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                RenameSpanKind.UnresolvedConflict));
                        }

                        foreach (var replacement in mergedReplacements)
                        {
                            var kind = GetRenameSpanKind(replacement.Kind);

                            if (_referenceSpanToLinkedRenameSpanMap.ContainsKey(replacement.OriginalSpan) && kind != RenameSpanKind.Complexified)
                            {
                                var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan(
                                    new InlineRenameLocation(newDocument, replacement.NewSpan), _session.ReplacementText, cancellationToken);
                                if (linkedRenameSpan.HasValue)
                                {
                                    if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                    {
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                            _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(
                                                linkedRenameSpan.Value.ToSpan(),
                                                SpanTrackingMode.EdgeInclusive,
                                                TrackingFidelityMode.Forward),
                                            kind);
                                    }
                                }
                                else
                                {
                                    // We might not have a renamable span if an alias conflict completely changed the text
                                    _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan].TrackingSpan,
                                        RenameSpanKind.None);

                                    if (_activeSpan.HasValue && _activeSpan.Value.IntersectsWith(replacement.OriginalSpan))
                                    {
                                        _activeSpan = null;
                                    }
                                }
                            }
                            else
                            {
                                if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                {
                                    _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                        _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(replacement.NewSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                        kind));
                                }
                            }
                        }
                    }

                    UpdateReadOnlyRegions();

                    // 3. Reset the undo state and notify the taggers.
                    this.ApplyReplacementText(updateSelection: false);
                    RaiseSpansChanged();
                }
            }
 /// <summary>
 /// Use this helper to register multiple refactorings (<paramref name="actions"/>).
 /// </summary>
 internal static void RegisterRefactorings <TCodeAction>(
     this CodeRefactoringContext context, ImmutableArray <TCodeAction> actions, TextSpan?applicableToSpan = null)
     where TCodeAction : CodeAction
 {
     if (!actions.IsDefault)
     {
         foreach (var action in actions)
         {
             if (applicableToSpan != null)
             {
                 context.RegisterRefactoring(action, applicableToSpan.Value);
             }
             else
             {
                 context.RegisterRefactoring(action);
             }
         }
     }
 }
        protected static Tuple<Document[], bool, TextSpan?[]> GetDocumentsAndSpans(FileAndSource[] sources, string language, bool addLanguageSpecificCodeAnalysisReference = true, string projectName = _testProjectName)
        {
            Assert.True(language == LanguageNames.CSharp || language == LanguageNames.VisualBasic, "Unsupported language");

            var spans = new TextSpan?[sources.Length];
            bool useSpans = false;

            for (int i = 0; i < sources.Length; i++)
            {
                string fileName = language == LanguageNames.CSharp ? "Test" + i + ".cs" : "Test" + i + ".vb";

                string source;
                int? pos;
                TextSpan? span;
                MarkupTestFile.GetPositionAndSpan(sources[i].Source, out source, out pos, out span);

                sources[i].Source = source;
                spans[i] = span;

                if (span != null)
                {
                    useSpans = true;
                }
            }

            Project project = CreateProject(sources, language, addLanguageSpecificCodeAnalysisReference, null, projectName);
            Document[] documents = project.Documents.ToArray();
            Assert.Equal(sources.Length, documents.Length);

            return Tuple.Create(documents, useSpans, spans);
        }
Exemple #36
0
 public void StartName(TextSpan textSpan, string name)
 {
     if (request != null)
      {
     if (currentSpan == null)
     {
        currentSpan = textSpan;
        this.Sink.StartName(textSpan, name);
     }
      }
 }
Exemple #37
0
            private IEnumerable <DiagnosticData> ConvertToLocalDiagnosticsWithoutCompilation(Document targetDocument, IEnumerable <Diagnostic> diagnostics, TextSpan?span = null)
            {
                var project = targetDocument.Project;

                Contract.ThrowIfTrue(project.SupportsCompilation);

                foreach (var diagnostic in diagnostics)
                {
                    var location = diagnostic.Location;
                    if (location.Kind != LocationKind.ExternalFile)
                    {
                        continue;
                    }

                    var lineSpan = location.GetLineSpan();

                    var documentIds = project.Solution.GetDocumentIdsWithFilePath(lineSpan.Path);
                    if (documentIds.IsEmpty || documentIds.All(id => id != targetDocument.Id))
                    {
                        continue;
                    }

                    yield return(DiagnosticData.Create(targetDocument, diagnostic));
                }
            }
            private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args)
            {
                AssertIsForeground();

                // This might be an event fired due to our own edit
                if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit)
                {
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_OnTextBufferChanged, CancellationToken.None))
                {
                    var trackingSpansAfterEdit = new NormalizedSpanCollection(GetEditableSpansForSnapshot(args.After).Select(ss => (Span)ss));
                    var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

                    var intersection = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);

                    if (intersection.Count == 0)
                    {
                        // In Razor we sometimes get formatting changes during inline rename that
                        // do not intersect with any of our spans. Ideally this shouldn't happen at
                        // all, but if it does happen we can just ignore it.
                        return;
                    }
                    else if (intersection.Count > 1)
                    {
                        Contract.Fail("we can't allow edits to touch multiple spans");
                    }

                    var intersectionSpan = intersection.Single();
                    var singleTrackingSpanTouched = GetEditableSpansForSnapshot(args.After).Single(ss => ss.IntersectsWith(intersectionSpan));
                    _activeSpan = _referenceSpanToLinkedRenameSpanMap.Where(kvp => kvp.Value.TrackingSpan.GetSpan(args.After).Contains(intersectionSpan)).Single().Key;

                    _session.UndoManager.OnTextChanged(this.ActiveTextview.Selection, singleTrackingSpanTouched);
                }
            }
Exemple #39
0
        public int FormatSpan(IVsTextLines pBuffer, TextSpan[] ts)
        {
            MSXML.IXMLDOMNode codeNode, snippetTypes, declarations, imports;

            int hr;

            if (ErrorHandler.Failed(hr = _session.GetSnippetNode("CodeSnippet:Code", out codeNode)))
            {
                return(hr);
            }

            if (ErrorHandler.Failed(hr = _session.GetHeaderNode("CodeSnippet:SnippetTypes", out snippetTypes)))
            {
                return(hr);
            }

            List <string> declList = new List <string>();

            if (ErrorHandler.Succeeded(hr = _session.GetSnippetNode("CodeSnippet:Declarations", out declarations)) &&
                declarations != null)
            {
                foreach (MSXML.IXMLDOMNode declType in declarations.childNodes)
                {
                    var id = declType.selectSingleNode("./CodeSnippet:ID");
                    if (id != null)
                    {
                        declList.Add(id.text);
                    }
                }
            }

            List <string> importList = new List <string>();

            if (ErrorHandler.Succeeded(hr = _session.GetSnippetNode("CodeSnippet:Imports", out imports)) &&
                imports != null)
            {
                foreach (MSXML.IXMLDOMNode import in imports.childNodes)
                {
                    var id = import.selectSingleNode("./CodeSnippet:Namespace");
                    if (id != null)
                    {
                        importList.Add(id.text);
                    }
                }
            }

            bool surroundsWith = false, surroundsWithStatement = false;

            foreach (MSXML.IXMLDOMNode snippetType in snippetTypes.childNodes)
            {
                if (snippetType.nodeName == "SnippetType")
                {
                    if (snippetType.text == SurroundsWith)
                    {
                        surroundsWith = true;
                    }
                    else if (snippetType.text == SurroundsWithStatement)
                    {
                        surroundsWithStatement = true;
                    }
                }
            }

            // get the indentation of where we're inserting the code...
            string baseIndentation = GetBaseIndentation(ts);
            int    startPosition;

            pBuffer.GetPositionOfLineIndex(ts[0].iStartLine, ts[0].iStartIndex, out startPosition);
            var insertTrackingPoint = _textView.TextBuffer.CurrentSnapshot.CreateTrackingPoint(startPosition, PointTrackingMode.Positive);

            TextSpan?endSpan = null;

            using (var edit = _textView.TextBuffer.CreateEdit()) {
                if (surroundsWith || surroundsWithStatement)
                {
                    // this is super annoyning...  Most languages can do a surround with and $selected$ can be
                    // an empty string and everything's the same.  But in Python we can't just have something like
                    // "while True: " without a pass statement.  So if we start off with an empty selection we
                    // need to insert a pass statement.  This is the purpose of the "SurroundsWithStatement"
                    // snippet type.
                    //
                    // But, to make things even more complicated, we don't have a good indication of what's the
                    // template text vs. what's the selected text.  We do have access to the original template,
                    // but all of the values have been replaced with their default values when we get called
                    // here.  So we need to go back and re-apply the template, except for the $selected$ part.
                    //
                    // Also, the text has \n, but the inserted text has been replaced with the appropriate newline
                    // character for the buffer.
                    var templateText = codeNode.text.Replace("\n", _textView.Options.GetNewLineCharacter());
                    foreach (var decl in declList)
                    {
                        string defaultValue;
                        if (ErrorHandler.Succeeded(_session.GetFieldValue(decl, out defaultValue)))
                        {
                            templateText = templateText.Replace("$" + decl + "$", defaultValue);
                        }
                    }
                    templateText = templateText.Replace("$end$", "");

                    // we can finally figure out where the selected text began witin the original template...
                    int selectedIndex = templateText.IndexOf("$selected$");
                    if (selectedIndex != -1)
                    {
                        var selection = _textView.Selection;

                        // now we need to get the indentation of the $selected$ element within the template,
                        // as we'll need to indent the selected code to that level.
                        string indentation = GetTemplateSelectionIndentation(templateText, selectedIndex);

                        var start = _selectionStart.GetPosition(_textView.TextBuffer.CurrentSnapshot);
                        var end   = _selectionEnd.GetPosition(_textView.TextBuffer.CurrentSnapshot);
                        if (end < start)
                        {
                            // we didn't actually have a selction, and our negative tracking pushed us
                            // back to the start of the buffer...
                            end = start;
                        }
                        var selectedSpan = Span.FromBounds(start, end);

                        if (surroundsWithStatement &&
                            String.IsNullOrWhiteSpace(_textView.TextBuffer.CurrentSnapshot.GetText(selectedSpan)))
                        {
                            // we require a statement here and the user hasn't selected any code to surround,
                            // so we insert a pass statement (and we'll select it after the completion is done)
                            edit.Replace(new Span(startPosition + selectedIndex, end - start), "pass");

                            // Surround With can be invoked with no selection, but on a line with some text.
                            // In that case we need to inject an extra new line.
                            var endLine = _textView.TextBuffer.CurrentSnapshot.GetLineFromPosition(end);
                            var endText = endLine.GetText().Substring(end - endLine.Start);
                            if (!String.IsNullOrWhiteSpace(endText))
                            {
                                edit.Insert(end, _textView.Options.GetNewLineCharacter());
                            }

                            // we want to leave the pass statement selected so the user can just
                            // continue typing over it...
                            var startLine = _textView.TextBuffer.CurrentSnapshot.GetLineFromPosition(startPosition + selectedIndex);
                            _selectEndSpan = true;
                            endSpan        = new TextSpan()
                            {
                                iStartLine  = startLine.LineNumber,
                                iEndLine    = startLine.LineNumber,
                                iStartIndex = baseIndentation.Length + indentation.Length,
                                iEndIndex   = baseIndentation.Length + indentation.Length + 4,
                            };
                        }

                        IndentSpan(
                            edit,
                            indentation,
                            _textView.TextBuffer.CurrentSnapshot.GetLineFromPosition(start).LineNumber + 1, // 1st line is already indented
                            _textView.TextBuffer.CurrentSnapshot.GetLineFromPosition(end).LineNumber
                            );
                    }
                }

                // we now need to update any code which was not selected  that we just inserted.
                IndentSpan(edit, baseIndentation, ts[0].iStartLine + 1, ts[0].iEndLine);

                edit.Apply();
            }

            if (endSpan != null)
            {
                _session.SetEndSpan(endSpan.Value);
            }

            // add any missing imports...
            AddMissingImports(
                importList,
                insertTrackingPoint.GetPoint(_textView.TextBuffer.CurrentSnapshot)
                ).Wait();

            return(hr);
        }
        public DiagnosticData(
            string id,
            string category,
            string message,
            string enuMessageForBingSearch,
            DiagnosticSeverity severity,
            DiagnosticSeverity defaultSeverity,
            bool isEnabledByDefault,
            int warningLevel,
            IReadOnlyList<string> customTags,
            ImmutableDictionary<string, string> properties,
            Workspace workspace,
            ProjectId projectId,
            DocumentId documentId = null,
            TextSpan? span = null,
            string mappedFilePath = null,
            int mappedStartLine = 0,
            int mappedStartColumn = 0,
            int mappedEndLine = 0,
            int mappedEndColumn = 0,
            string originalFilePath = null,
            int originalStartLine = 0,
            int originalStartColumn = 0,
            int originalEndLine = 0,
            int originalEndColumn = 0,
            string title = null,
            string description = null,
            string helpLink = null)
        {
            this.Id = id;
            this.Category = category;
            this.Message = message;
            this.ENUMessageForBingSearch = enuMessageForBingSearch;

            this.Severity = severity;
            this.DefaultSeverity = defaultSeverity;
            this.IsEnabledByDefault = isEnabledByDefault;
            this.WarningLevel = warningLevel;
            this.CustomTags = customTags;
            this.Properties = properties;

            this.Workspace = workspace;
            this.ProjectId = projectId;
            this.DocumentId = documentId;

            this.MappedStartLine = mappedStartLine;
            this.MappedStartColumn = mappedStartColumn;
            this.MappedEndLine = mappedEndLine;
            this.MappedEndColumn = mappedEndColumn;
            this.MappedFilePath = mappedFilePath;

            this.OriginalStartLine = originalStartLine;
            this.OriginalStartColumn = originalStartColumn;
            this.OriginalEndLine = originalEndLine;
            this.OriginalEndColumn = originalEndColumn;
            this.OriginalFilePath = originalFilePath;

            _textSpan = span;

            this.Title = title;
            this.Description = description;
            this.HelpLink = helpLink;
        }
 public Task <IList <TextChange> > GetFormattingChangesAsync(Document document, TextSpan?textSpan, DocumentOptionSet?documentOptions, CancellationToken cancellationToken)
 {
     return(_service.GetFormattingChangesAsync(document, textSpan, cancellationToken));
 }
Exemple #42
0
        public async Task <LSP.CompletionList?> HandleRequestAsync(LSP.CompletionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            Contract.ThrowIfNull(document);

            // C# and VB share the same LSP language server, and thus share the same default trigger characters.
            // We need to ensure the trigger character is valid in the document's language. For example, the '{'
            // character, while a trigger character in VB, is not a trigger character in C#.
            if (request.Context != null &&
                request.Context.TriggerKind == LSP.CompletionTriggerKind.TriggerCharacter &&
                !char.TryParse(request.Context.TriggerCharacter, out var triggerCharacter) &&
                !char.IsLetterOrDigit(triggerCharacter) &&
                !IsValidTriggerCharacterForDocument(document, triggerCharacter))
            {
                return(null);
            }

            var completionOptions = GetCompletionOptions(document) with {
                UpdateImportCompletionCacheInBackground = true
            };
            var completionService = document.GetRequiredLanguageService <CompletionService>();
            var documentText      = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var completionListResult = await GetFilteredCompletionListAsync(request, documentText, document, completionOptions, completionService, cancellationToken).ConfigureAwait(false);

            if (completionListResult == null)
            {
                return(null);
            }

            var(list, isIncomplete, resultId) = completionListResult.Value;

            var lspVSClientCapability     = context.ClientCapabilities.HasVisualStudioLspCapability() == true;
            var snippetsSupported         = context.ClientCapabilities.TextDocument?.Completion?.CompletionItem?.SnippetSupport ?? false;
            var commitCharactersRuleCache = new Dictionary <ImmutableArray <CharacterSetModificationRule>, string[]>(CommitCharacterArrayComparer.Instance);

            // Feature flag to enable the return of TextEdits instead of InsertTexts (will increase payload size).
            Contract.ThrowIfNull(context.Solution);
            var returnTextEdits = _globalOptions.GetOption(LspOptions.LspCompletionFeatureFlag);

            TextSpan?defaultSpan = null;

            LSP.Range?defaultRange = null;
            if (returnTextEdits)
            {
                // We want to compute the document's text just once.
                documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                // We use the first item in the completion list as our comparison point for span
                // and range for optimization when generating the TextEdits later on.
                var completionChange = await completionService.GetChangeAsync(
                    document, list.Items.First(), cancellationToken : cancellationToken).ConfigureAwait(false);

                // If possible, we want to compute the item's span and range just once.
                // Individual items can override this range later.
                defaultSpan  = completionChange.TextChange.Span;
                defaultRange = ProtocolConversions.TextSpanToRange(defaultSpan.Value, documentText);
            }

            var supportsCompletionListData = context.ClientCapabilities.HasCompletionListDataCapability();
            var completionResolveData      = new CompletionResolveData()
            {
                ResultId = resultId,
            };
            var stringBuilder = new StringBuilder();

            using var _ = ArrayBuilder <LSP.CompletionItem> .GetInstance(out var lspCompletionItems);

            foreach (var item in list.Items)
            {
                var completionItemResolveData = supportsCompletionListData ? null : completionResolveData;
                var lspCompletionItem         = await CreateLSPCompletionItemAsync(
                    request, document, item, completionItemResolveData, lspVSClientCapability, commitCharactersRuleCache,
                    completionService, context.ClientName, returnTextEdits, snippetsSupported, stringBuilder, documentText,
                    defaultSpan, defaultRange, cancellationToken).ConfigureAwait(false);

                lspCompletionItems.Add(lspCompletionItem);
            }

            var completionList = new LSP.VSInternalCompletionList
            {
                Items          = lspCompletionItems.ToArray(),
                SuggestionMode = list.SuggestionModeItem != null,
                IsIncomplete   = isIncomplete,
            };

            if (supportsCompletionListData)
            {
                completionList.Data = completionResolveData;
            }

            if (context.ClientCapabilities.HasCompletionListCommitCharactersCapability())
            {
                PromoteCommonCommitCharactersOntoList(completionList);
            }

            var optimizedCompletionList = new LSP.OptimizedVSCompletionList(completionList);

            return(optimizedCompletionList);

            // Local functions
            bool IsValidTriggerCharacterForDocument(Document document, char triggerCharacter)
            {
                if (document.Project.Language == LanguageNames.CSharp)
                {
                    return(_csharpTriggerCharacters.Contains(triggerCharacter));
                }
                else if (document.Project.Language == LanguageNames.VisualBasic)
                {
                    return(_vbTriggerCharacters.Contains(triggerCharacter));
                }

                // Typescript still calls into this for completion.
                // Since we don't know what their trigger characters are, just return true.
                return(true);
            }
        private StringExpressionChain(BinaryExpressionSyntax addExpression, IEnumerable <ExpressionSyntax> expressions, TextSpan?span = null)
        {
            OriginalExpression = addExpression;
            Expressions        = ImmutableArray.CreateRange(expressions);
            Span = span;

            foreach (ExpressionSyntax expression in expressions)
            {
                SyntaxKind kind = expression.Kind();

                if (kind == SyntaxKind.StringLiteralExpression)
                {
                    if (((LiteralExpressionSyntax)expression).IsVerbatimStringLiteral())
                    {
                        ContainsVerbatimLiteral = true;
                    }
                    else
                    {
                        ContainsRegularLiteral = true;
                    }
                }
                else
                {
                    ContainsExpression = true;

                    if (kind == SyntaxKind.InterpolatedStringExpression)
                    {
                        ContainsInterpolatedStringExpression = true;

                        if (((InterpolatedStringExpressionSyntax)expression).IsVerbatim())
                        {
                            ContainsVerbatimInterpolatedStringExpression = true;
                        }
                        else
                        {
                            ContainsRegularInterpolatedStringExpression = true;
                        }
                    }
                }
            }
        }
            private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args)
            {
                AssertIsForeground();

                // This might be an event fired due to our own edit
                if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit)
                {
                    return;
                }

                using (Logger.LogBlock(FunctionId.Rename_OnTextBufferChanged, CancellationToken.None))
                {
                    var trackingSpansAfterEdit = new NormalizedSpanCollection(GetEditableSpansForSnapshot(args.After).Select(ss => (Span)ss));
                    var spansTouchedInEdit = new NormalizedSpanCollection(args.Changes.Select(c => c.NewSpan));

                    var intersectionSpans = NormalizedSpanCollection.Intersection(trackingSpansAfterEdit, spansTouchedInEdit);
                    if (intersectionSpans.Count == 0)
                    {
                        // In Razor we sometimes get formatting changes during inline rename that
                        // do not intersect with any of our spans. Ideally this shouldn't happen at
                        // all, but if it does happen we can just ignore it.
                        return;
                    }

                    // Cases with invalid identifiers may cause there to be multiple intersection
                    // spans, but they should still all map to a single tracked rename span (e.g.
                    // renaming "two" to "one two three" may be interpreted as two distinct
                    // additions of "one" and "three").
                    var boundingIntersectionSpan = Span.FromBounds(intersectionSpans.First().Start, intersectionSpans.Last().End);
                    var trackingSpansTouched = GetEditableSpansForSnapshot(args.After).Where(ss => ss.IntersectsWith(boundingIntersectionSpan));
                    Contract.Assert(trackingSpansTouched.Count() == 1);

                    var singleTrackingSpanTouched = trackingSpansTouched.Single();
                    _activeSpan = _referenceSpanToLinkedRenameSpanMap.Where(kvp => kvp.Value.TrackingSpan.GetSpan(args.After).Contains(boundingIntersectionSpan)).Single().Key;
                    _session.UndoManager.OnTextChanged(this.ActiveTextview.Selection, singleTrackingSpanTouched);
                }
            }
Exemple #45
0
        protected static void AnalyzeDocumentCore(DiagnosticAnalyzer analyzer, Document document, Action <Diagnostic> addDiagnostic, TextSpan?span = null, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = true)
        {
            SemanticModel semanticModel = document.GetSemanticModelAsync().Result;
            Compilation   compilation   = semanticModel.Compilation;

            compilation = EnableAnalyzer(analyzer, compilation);

            ImmutableArray <Diagnostic> diagnostics = compilation.GetAnalyzerDiagnostics(new[] { analyzer }, onAnalyzerException: onAnalyzerException, logAnalyzerExceptionAsDiagnostics: logAnalyzerExceptionAsDiagnostics);

            foreach (Diagnostic diagnostic in diagnostics)
            {
                if (!span.HasValue ||
                    diagnostic.Location == Location.None ||
                    diagnostic.Location.IsInMetadata ||
                    (diagnostic.Location.SourceTree == semanticModel.SyntaxTree &&
                     span.Value.Contains(diagnostic.Location.SourceSpan)))
                {
                    addDiagnostic(diagnostic);
                }
            }
        }
 public Task <IEnumerable <Diagnostic> > GetAllDiagnosticsAsync(Document document, TextSpan?filterSpan)
 {
     return(GetDiagnosticsAsync(document.Project, document, filterSpan, getDocumentDiagnostics: true, getProjectDiagnostics: true));
 }
Exemple #47
0
            private async Task <TextSpan?> GetSpanAsync(SnapshotSpan range)
            {
                // First, ensure that the snapshot we're being asked about is for an actual
                // roslyn document.  This can fail, for example, in projection scenarios where
                // we are called with a range snapshot that refers to the projection buffer
                // and not the actual roslyn code that is being projected into it.
                var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

                if (document == null)
                {
                    return(null);
                }

                // Also make sure the range is from the same buffer that this source was created for
                Contract.ThrowIfFalse(
                    range.Snapshot.TextBuffer.Equals(_subjectBuffer),
                    $"Invalid text buffer passed to {nameof(HasSuggestedActionsAsync)}");

                // Next, before we do any async work, acquire the user's selection, directly grabbing
                // it from the UI thread if htat's what we're on. That way we don't have any reentrancy
                // blocking concerns if VS wants to block on this call (for example, if the user
                // explicitly invokes the 'show smart tag' command).
                //
                // This work must happen on the UI thread as it needs to access the _textView's mutable
                // state.
                //
                // Note: we may be called in one of two VS scenarios:
                //      1) User has moved caret to a new line.  In this case VS will call into us in the
                //         bg to see if we have any suggested actions for this line.  In order to figure
                //         this out, we need to see what selectoin the user has (for refactorings), which
                //         necessitates going back to the fg.
                //
                //      2) User moves to a line and immediately hits ctrl-dot.  In this case, on the UI
                //         thread VS will kick us off and then immediately block to get the results so
                //         that they can expand the lightbulb.  In this case we cannot do BG work first,
                //         then call back into the UI thread to try to get the user selection.  This will
                //         deadlock as the UI thread is blocked on us.
                //
                // There are two solution to '2'.  Either introduce reentrancy (which we really don't
                // like to do), or just ensure that we acquire and get the users selection up front.
                // This means that when we're called from the UI therad, we never try to go back to the
                // UI thread.
                TextSpan?selection = null;

                if (IsForeground())
                {
                    selection = TryGetCodeRefactoringSelection(range);
                }
                else
                {
                    await InvokeBelowInputPriority(() =>
                    {
                        // Make sure we were not disposed between kicking off this work and getting
                        // to this point.
                        if (IsDisposed)
                        {
                            return;
                        }

                        selection = TryGetCodeRefactoringSelection(range);
                    }).ConfigureAwait(false);
                }

                return(selection);
            }
 public EditClassifier(
     CSharpEditAndContinueAnalyzer analyzer,
     List<RudeEditDiagnostic> diagnostics,
     SyntaxNode oldNode,
     SyntaxNode newNode,
     EditKind kind,
     Match<SyntaxNode> match = null,
     TextSpan? span = null)
 {
     _analyzer = analyzer;
     _diagnostics = diagnostics;
     _oldNode = oldNode;
     _newNode = newNode;
     _kind = kind;
     _span = span;
     _match = match;
 }
Exemple #49
0
            private async Task <IEnumerable <Diagnostic> > ComputeDiagnosticAnalyzerDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan?spanOpt, CancellationToken cancellationToken)
            {
                // quick optimization to reduce allocations.
                if (analyzerDriverOpt == null || !_owner.SupportAnalysisKind(analyzer, document.Project.Language, kind))
                {
                    return(ImmutableArray <Diagnostic> .Empty);
                }

                if (!await SemanticAnalysisEnabled(document, analyzer, kind, cancellationToken).ConfigureAwait(false))
                {
                    return(ImmutableArray <Diagnostic> .Empty);
                }

                // REVIEW: more unnecessary allocations just to get diagnostics per analyzer
                var oneAnalyzers = ImmutableArray.Create(analyzer);

                switch (kind)
                {
                case AnalysisKind.Syntax:
                    var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                    var diagnostics = await analyzerDriverOpt.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                    return(diagnostics.ToImmutableArrayOrEmpty());

                case AnalysisKind.Semantic:
                    var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    diagnostics = await analyzerDriverOpt.GetAnalyzerSemanticDiagnosticsAsync(model, spanOpt, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                    return(diagnostics.ToImmutableArrayOrEmpty());

                default:
                    return(Contract.FailWithReturn <ImmutableArray <Diagnostic> >("shouldn't reach here"));
                }
            }