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; }
public ReplaceAction(string description, SyntaxNode oldNode, SyntaxNode newNode, TextSpan? suggestedSpan = null) { this.Description = description; this.OldNode = oldNode; this.NewNode = newNode; this.SuggestedSpan = suggestedSpan; }
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; }
public void SetContext(ParseRequest parseRequest) { this.request = parseRequest; this.currentSpan = null; braces = new List<TextSpan[]>(); }
/// <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); }
/// <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); }
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); }
private static bool IsBetter(Microsoft.CodeAnalysis.SignatureHelp.SignatureHelpItems bestItems, TextSpan?currentTextSpan) { return(bestItems == null || currentTextSpan?.Start > bestItems.ApplicableSpan.Start); }
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())); }
/// <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));
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)); }
private Action <Diagnostic> GetAddDiagnostic(SyntaxTree tree, TextSpan?span, DiagnosticAnalyzer analyzer, bool isSyntaxDiagnostic) { return(GetAddDiagnostic(tree, span, analyzer, false, _addDiagnostic, _addLocalDiagnosticOpt, _addNonLocalDiagnosticOpt)); }
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; }
internal ExpressionChain(BinaryExpressionSyntax binaryExpression, TextSpan?span = null) { BinaryExpression = binaryExpression; Span = span; }
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)); } }
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); }
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(); } }
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)); }
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()); }
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);
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(); }
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); }
public void StartName(TextSpan textSpan, string name) { if (request != null) { if (currentSpan == null) { currentSpan = textSpan; this.Sink.StartName(textSpan, name); } } }
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); } }
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)); }
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); } }
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)); }
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; }
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")); } }