private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken token) { var sourceText = await document.GetTextAsync(token).ConfigureAwait(false); var startIndex = sourceText.Lines.IndexOf(diagnostic.Location.SourceSpan.Start); int endIndex = startIndex; for (var i = startIndex + 1; i < sourceText.Lines.Count; i++) { if (!string.IsNullOrWhiteSpace(sourceText.Lines[i].ToString())) { endIndex = i - 1; break; } } if (endIndex >= (startIndex + 1)) { var replaceSpan = TextSpan.FromBounds(sourceText.Lines[startIndex + 1].SpanIncludingLineBreak.Start, sourceText.Lines[endIndex].SpanIncludingLineBreak.End); var newSourceText = sourceText.Replace(replaceSpan, string.Empty); return document.WithText(newSourceText); } return document; }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Location location, CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var sourceSpan = location.SourceSpan; return document.WithText(text.WithChanges(GetTextChange(text, sourceSpan))); }
private bool TryGetDocumentWithFullyQualifiedTypeName(Document document, out TextSpan updatedTextSpan, out Document documentWithFullyQualifiedTypeName) { documentWithFullyQualifiedTypeName = null; updatedTextSpan = default(TextSpan); var surfaceBufferFieldSpan = new VsTextSpan[1]; if (snippetExpansionClient.ExpansionSession.GetFieldSpan(_fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK) { return false; } SnapshotSpan subjectBufferFieldSpan; if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out subjectBufferFieldSpan)) { return false; } var originalTextSpan = new TextSpan(subjectBufferFieldSpan.Start, subjectBufferFieldSpan.Length); updatedTextSpan = new TextSpan(subjectBufferFieldSpan.Start, _fullyQualifiedName.Length); var textChange = new TextChange(originalTextSpan, _fullyQualifiedName); var newText = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None).WithChanges(textChange); documentWithFullyQualifiedTypeName = document.WithText(newText); return true; }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); TextChange textChange = new TextChange(new TextSpan(diagnostic.Location.SourceSpan.Start, 1), string.Empty); return document.WithText(text.WithChanges(textChange)); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken token) { var newLine = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); var sourceText = await document.GetTextAsync(token).ConfigureAwait(false); var textChange = new TextChange(diagnostic.Location.SourceSpan, newLine); return document.WithText(sourceText.WithChanges(textChange)); }
private async Task<Document> ReplaceWithUtcNowAsync(Document document, TextSpan span, CancellationToken cancellationToken) { var text = await document.GetTextAsync(); var repl = "DateTime.UtcNow"; if (Regex.Replace(text.GetSubText(span).ToString(),@"\s+",string.Empty) == "System.DateTime.Now") repl = "System.DateTime.UtcNow"; var newtext = text.Replace(span, repl); return document.WithText(newtext); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var indentationOptions = IndentationOptions.FromDocument(document); SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return document.WithText(sourceText.WithChanges(FixDiagnostic(indentationOptions, sourceText, diagnostic))); }
/// <summary> /// Fixes the whitespace at the end of a document. /// </summary> /// <param name="document">The document to be changed.</param> /// <param name="diagnostic">The diagnostic to fix.</param> /// <param name="newlineAtEndOfFile">A <see cref="EndOfFileHandling"/> value indicating the desired behavior.</param> /// <param name="cancellationToken">The cancellation token associated with the fix action.</param> /// <returns>The transformed document.</returns> private static async Task<Document> FixEndOfFileAsync(Document document, Diagnostic diagnostic, EndOfFileHandling newlineAtEndOfFile, CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); string replacement = newlineAtEndOfFile == EndOfFileHandling.Omit ? string.Empty : "\r\n"; return document.WithText(text.WithChanges(new TextChange(diagnostic.Location.SourceSpan, replacement))); }
private static async Task<Document> GetSingleAnalyzerDocumentAsync(ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int maxNumberOfIterations, CancellationToken cancellationToken) { var previousDiagnostics = ImmutableArray.Create<Diagnostic>(); bool done; do { var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { break; } if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics)) { break; } if (--maxNumberOfIterations < 0) { Assert.True(false, "The upper limit for the number of code fix iterations was exceeded"); } previousDiagnostics = analyzerDiagnostics; done = true; for (var i = 0; i < analyzerDiagnostics.Length; i++) { var actions = new List<CodeAction>(); var context = new CodeFixContext(document, analyzerDiagnostics[i], (a, d) => actions.Add(a), cancellationToken); await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false); if (actions.Count > 0) { var fixedDocument = await ApplyFixAsync(document, actions.ElementAt(codeFixIndex.GetValueOrDefault(0)), cancellationToken).ConfigureAwait(false); if (fixedDocument != document) { done = false; var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document. document = document.WithText(newText); break; } } } } while (!done); return document; }
private Document DeleteMember(Document document, SyntaxNode node) { var text = document.GetTextAsync(CancellationToken.None) .WaitAndGetResult_CodeModel(CancellationToken.None); // We want to delete all the leading trivia from the node back to, // but not including: // * the first preprocessor directive // - or - // * the first comment after a white-space only line // We also want to delete all the trailing trivia var deletionEnd = node.FullSpan.End; var deletionStart = node.SpanStart; int contiguousEndOfLines = 0; foreach (var trivia in node.GetLeadingTrivia().Reverse()) { if (trivia.IsDirective) { break; } if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) { if (contiguousEndOfLines > 0) { break; } else { contiguousEndOfLines++; } } else if (trivia.Kind() != SyntaxKind.WhitespaceTrivia) { contiguousEndOfLines = 0; } deletionStart = trivia.FullSpan.Start; } text = text.Replace(TextSpan.FromBounds(deletionStart, deletionEnd), string.Empty); return document.WithText(text); }
private static Document ForkNewDocument(CopyData copyData, Document document, TextSpan span) { // here we assume paste data is what is copied before. // we will check this assumption when things are actually pasted. var newText = document.GetTextAsync().Result.ToString().Remove(span.Start, span.Length).Insert(span.Start, copyData.Text); // fork solution return document.WithText(SourceText.From(newText)); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return document.WithText(sourceText.WithChanges(FixDiagnostic(settings.Indentation, sourceText, diagnostic))); }
private void ApplyDocumentToBuffer(Document document, SpanChange spanSource, out SourceTextContainer container, out Document documentBackedByTextBuffer) { var contentTypeService = document.Project.LanguageServices.GetService<IContentTypeLanguageService>(); var contentType = contentTypeService.GetDefaultContentType(); TextView.TextBuffer.ChangeContentType(contentType, null); var documentText = document.GetTextAsync().Result.ToString(); SpanToShow = spanSource.GetSpan(); using (var edit = TextView.TextBuffer.CreateEdit()) { edit.Replace(new Span(0, TextView.TextBuffer.CurrentSnapshot.Length), documentText); edit.Apply(); } container = TextView.TextBuffer.AsTextContainer(); documentBackedByTextBuffer = document.WithText(container.CurrentText); }
protected override bool TryGetSimplifiedTypeNameInCaseContext(Document document, string fullyQualifiedTypeName, string firstEnumMemberName, int startPosition, int endPosition, CancellationToken cancellationToken, out string simplifiedTypeName) { simplifiedTypeName = string.Empty; var typeAnnotation = new SyntaxAnnotation(); var str = "case " + fullyQualifiedTypeName + "." + firstEnumMemberName + ":" + Environment.NewLine + " break;"; var textChange = new TextChange(new TextSpan(startPosition, endPosition - startPosition), str); var typeSpanToAnnotate = new TextSpan(startPosition + "case ".Length, fullyQualifiedTypeName.Length); var textWithCaseAdded = document.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken).WithChanges(textChange); var documentWithCaseAdded = document.WithText(textWithCaseAdded); var syntaxRoot = documentWithCaseAdded.GetSyntaxRootSynchronously(cancellationToken); var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == typeSpanToAnnotate); if (nodeToReplace == null) { return false; } var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); var documentWithAnnotations = documentWithCaseAdded.WithSyntaxRoot(updatedRoot); var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).Result; simplifiedTypeName = simplifiedDocument.GetSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); return true; }
private static async Task<Document> RemoveSemicolonTextAsync(Document document, SyntaxToken token, CancellationToken cancellationToken) { SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); TextLine line = sourceText.Lines.GetLineFromPosition(token.SpanStart); if (sourceText.ToString(line.Span).Trim() == token.Text) { // remove the line containing the semicolon token TextChange textChange = new TextChange(line.SpanIncludingLineBreak, string.Empty); return document.WithText(sourceText.WithChanges(textChange)); } else { // remove just the semicolon TextChange textChange = new TextChange(token.Span, string.Empty); return document.WithText(sourceText.WithChanges(textChange)); } }
/// <summary> /// Removes trailing whitespace. /// </summary> /// <param name="document">The document to be changed.</param> /// <param name="diagnostic">The diagnostic to fix.</param> /// <param name="cancellationToken">The cancellation token associated with the fix action.</param> /// <returns>The transformed document.</returns> private static async Task<Document> RemoveWhitespaceAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return document.WithText(text.WithChanges(new TextChange(diagnostic.Location.SourceSpan, string.Empty))); }
private Document Delete(Document document, AttributeSyntax node) { var attributeList = node.FirstAncestorOrSelf<AttributeListSyntax>(); // If we don't have anything left, then just delete the whole attribute list. if (attributeList.Attributes.Count == 1) { var text = document.GetTextAsync(CancellationToken.None) .WaitAndGetResult_CodeModel(CancellationToken.None); // Note that we want to keep all leading trivia and delete all trailing trivia. var deletionStart = attributeList.SpanStart; var deletionEnd = attributeList.FullSpan.End; text = text.Replace(TextSpan.FromBounds(deletionStart, deletionEnd), string.Empty); return document.WithText(text); } else { var newAttributeList = attributeList.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia); return document.ReplaceNodeAsync(attributeList, newAttributeList, CancellationToken.None) .WaitAndGetResult_CodeModel(CancellationToken.None); } }
private static async Task<Document> RemoveSemicolonTextAsync(Document document, SyntaxToken token, CancellationToken cancellationToken) { TextChange textChange; SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); TextLine line = sourceText.Lines.GetLineFromPosition(token.SpanStart); if (sourceText.ToString(line.Span).Trim() == token.Text) { // remove the line containing the semicolon token textChange = new TextChange(line.SpanIncludingLineBreak, string.Empty); return document.WithText(sourceText.WithChanges(textChange)); } TextSpan spanToRemove; var whitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(token.LeadingTrivia); if (whitespaceIndex >= 0) { spanToRemove = TextSpan.FromBounds(token.LeadingTrivia[whitespaceIndex].Span.Start, token.Span.End); } else { var previousToken = token.GetPreviousToken(); whitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia); if (whitespaceIndex >= 0) { spanToRemove = TextSpan.FromBounds(previousToken.TrailingTrivia[whitespaceIndex].Span.Start, token.Span.End); } else { spanToRemove = token.Span; } } textChange = new TextChange(spanToRemove, string.Empty); return document.WithText(sourceText.WithChanges(textChange)); }
private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int numberOfIterations, CancellationToken cancellationToken) { int expectedNumberOfIterations = numberOfIterations; if (numberOfIterations < 0) { numberOfIterations = -numberOfIterations; } var previousDiagnostics = ImmutableArray.Create<Diagnostic>(); var fixAllProvider = codeFixProvider.GetFixAllProvider(); if (fixAllProvider == null) { return null; } bool done; do { var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { break; } if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics)) { break; } if (--numberOfIterations < 0) { Assert.True(false, "The upper limit for the number of fix all iterations was exceeded"); } string equivalenceKey = null; foreach (var diagnostic in analyzerDiagnostics) { if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id)) { // do not pass unsupported diagnostics to a code fix provider continue; } var actions = new List<CodeAction>(); var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken); await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false); if (actions.Count > (codeFixIndex ?? 0)) { equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey; break; } } previousDiagnostics = analyzerDiagnostics; done = true; FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics); IEnumerable<string> analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id); IEnumerable<string> compilerDiagnosticIds = codeFixProvider.FixableDiagnosticIds.Where(x => x.StartsWith("CS", StringComparison.Ordinal)); IEnumerable<string> disabledDiagnosticIds = document.Project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key); IEnumerable<string> relevantIds = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct(); FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken); CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false); if (action == null) { return document; } var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false); if (fixedDocument != document) { done = false; var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document. document = document.WithText(newText); } } while (!done); if (expectedNumberOfIterations >= 0) { Assert.Equal($"{expectedNumberOfIterations} iterations", $"{expectedNumberOfIterations - numberOfIterations} iterations"); } return document; }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return document.WithText(text.WithChanges(GetTextChange(root, text, diagnostic))); }
private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int maxNumberOfIterations, CancellationToken cancellationToken) { var previousDiagnostics = ImmutableArray.Create<Diagnostic>(); var fixAllProvider = codeFixProvider.GetFixAllProvider(); if (fixAllProvider == null) { return null; } bool done; do { var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { break; } if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics)) { break; } if (--maxNumberOfIterations < 0) { Assert.True(false, "The upper limit for the number of fix all iterations was exceeded"); } string equivalenceKey = null; foreach (var diagnostic in analyzerDiagnostics) { var actions = new List<CodeAction>(); var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken); await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false); if (actions.Count > (codeFixIndex ?? 0)) { equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey; break; } } previousDiagnostics = analyzerDiagnostics; done = true; FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics); FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, codeFixProvider.FixableDiagnosticIds, fixAllDiagnosticProvider, cancellationToken); CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false); if (action == null) { return document; } var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false); if (fixedDocument != document) { done = false; var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document. document = document.WithText(newText); } } while (!done); return document; }
private static async Task<Document> RecreateDocumentAsync(Document document, CancellationToken cancellationToken) { var newText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); newText = newText.WithChanges(new TextChange(new TextSpan(0, 0), " ")); newText = newText.WithChanges(new TextChange(new TextSpan(0, 1), string.Empty)); return document.WithText(newText); }