public IFormattingRule CreateRule(Document document, int position) { var visualStudioWorkspace = document.Project.Solution.Workspace as VisualStudioWorkspaceImpl; if (visualStudioWorkspace == null) { return _noopRule; } var containedDocument = visualStudioWorkspace.GetHostDocument(document.Id) as ContainedDocument; if (containedDocument == null) { return _noopRule; } var textContainer = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None).Container; var buffer = textContainer.TryGetTextBuffer() as IProjectionBuffer; if (buffer == null) { return _noopRule; } using (var pooledObject = SharedPools.Default<List<TextSpan>>().GetPooledObject()) { var spans = pooledObject.Object; var root = document.GetSyntaxRootAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var text = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); spans.AddRange(containedDocument.GetEditorVisibleSpans()); for (var i = 0; i < spans.Count; i++) { var visibleSpan = spans[i]; if (visibleSpan.IntersectsWith(position) || visibleSpan.End == position) { return containedDocument.GetBaseIndentationRule(root, text, spans, i); } } // in razor (especially in @helper tag), it is possible for us to be asked for next line of visible span var line = text.Lines.GetLineFromPosition(position); if (line.LineNumber > 0) { line = text.Lines[line.LineNumber - 1]; // find one that intersects with previous line for (var i = 0; i < spans.Count; i++) { var visibleSpan = spans[i]; if (visibleSpan.IntersectsWith(line.Span)) { return containedDocument.GetBaseIndentationRule(root, text, spans, i); } } } throw new InvalidOperationException(); } }
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))); }
public AbstractSourceTreeItem(Document document, TextSpan sourceSpan, ushort glyphIndex, int commonPathElements = 0) : base(glyphIndex) { // We store the document ID, line and offset for navigation so that we // still provide reasonable navigation if the user makes changes elsewhere // in the document other than inserting or removing lines. _workspace = document.Project.Solution.Workspace; _documentId = document.Id; _projectName = document.Project.Name; _filePath = GetFilePath(document, commonPathElements); _sourceSpan = sourceSpan; var text = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var textLine = text.Lines.GetLineFromPosition(_sourceSpan.Start); _textLineString = textLine.ToString(); _lineNumber = textLine.LineNumber; _offset = sourceSpan.Start - textLine.Start; var spanInSecondaryBuffer = text.GetVsTextSpanForLineOffset(_lineNumber, _offset); VsTextSpan spanInPrimaryBuffer; var succeeded = spanInSecondaryBuffer.TryMapSpanFromSecondaryBufferToPrimaryBuffer(_workspace, _documentId, out spanInPrimaryBuffer); _mappedLineNumber = succeeded ? spanInPrimaryBuffer.iStartLine : _lineNumber; _mappedOffset = succeeded ? spanInPrimaryBuffer.iStartIndex : _offset; }
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; }
public static async Task<bool> IsTriggerCharacter([NotNull] this ISignatureHelpProvider provider, Document document, int position) { if (provider == null) throw new ArgumentNullException(nameof(provider)); var text = await document.GetTextAsync().ConfigureAwait(false); var character = text.GetSubText(new TextSpan(position, 1))[0]; return provider.IsTriggerCharacter(character); }
public static async Task<IEnumerable<LinePositionSpanTextChange>> GetFormattingChangesAfterKeystroke(Workspace workspace, OptionSet options, Document document, int position, char character) { var tree = await document.GetSyntaxTreeAsync(); if (character == '\n') { // format previous line on new line var lines = (await document.GetTextAsync()).Lines; var targetLine = lines[lines.GetLineFromPosition(position).LineNumber - 1]; if (!string.IsNullOrWhiteSpace(targetLine.Text.ToString(targetLine.Span))) { return await GetFormattingChangesForRange(workspace, options, document, targetLine.Start, targetLine.End); } } else if (character == '}' || character == ';') { // format after ; and } var node = FindFormatTarget(tree, position); if (node != null) { return await GetFormattingChangesForRange(workspace, options, document, node.FullSpan.Start, node.FullSpan.End); } } return Enumerable.Empty<LinePositionSpanTextChange>(); }
public SourceListItem(Document document, TextSpan sourceSpan, ushort glyphIndex) : base(glyphIndex) { _workspace = document.Project.Solution.Workspace; // We store the document ID, line and offset for navigation so that we // still provide reasonable navigation if the user makes changes elsewhere // in the document other than inserting or removing lines. _documentId = document.Id; var filePath = document.FilePath; var text = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None); var textLine = text.Lines.GetLineFromPosition(sourceSpan.Start); _lineNumber = textLine.LineNumber; _offset = sourceSpan.Start - textLine.Start; var spanInSecondaryBuffer = text.GetVsTextSpanForLineOffset(_lineNumber, _offset); VsTextSpan spanInPrimaryBuffer; var succeeded = spanInSecondaryBuffer.TryMapSpanFromSecondaryBufferToPrimaryBuffer(_workspace, document.Id, out spanInPrimaryBuffer); var mappedLineNumber = succeeded ? spanInPrimaryBuffer.iStartLine : _lineNumber; var mappedOffset = succeeded ? spanInPrimaryBuffer.iStartIndex : _offset; SetDisplayProperties(filePath, mappedLineNumber, mappedOffset, _lineNumber, _offset, textLine.ToString(), sourceSpan.Length); }
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; }
public static new async Task<SemanticDocument> CreateAsync(Document document, CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); return new SemanticDocument(document, text, root.SyntaxTree, root, model); }
private void UpdateBuffer(Document document, SpanChange spanSource, out SourceTextContainer container, out Document documentBackedByTextBuffer) { if (_previewWorkspace != null) { _previewWorkspace.CloseDocument(_currentDocument, _previewWorkspace.CurrentSolution.GetDocument(_currentDocument).GetTextAsync().Result); // Put the new document into the current preview solution var updatedSolution = _previewWorkspace.CurrentSolution.WithDocumentText(document.Id, document.GetTextAsync().Result); var updatedDocument = updatedSolution.GetDocument(document.Id); ApplyDocumentToBuffer(updatedDocument, spanSource, out container, out documentBackedByTextBuffer); _previewWorkspace.TryApplyChanges(documentBackedByTextBuffer.Project.Solution); _previewWorkspace.OpenDocument(document.Id); _currentDocument = document.Id; } else { _currentDocument = document.Id; ApplyDocumentToBuffer(document, spanSource, out container, out documentBackedByTextBuffer); _previewWorkspace = new PreviewDialogWorkspace(documentBackedByTextBuffer.Project.Solution); _previewWorkspace.OpenDocument(document.Id); } }
internal static async Task<DebugLocationInfo> GetInfoAsync(Document document, int position, CancellationToken cancellationToken) { string name = null; int lineOffset = 0; // Note that we get the current partial solution here. Technically, this means that we may // not fully understand the signature of the member. But that's ok. We just need this // symbol so we can create a display string to put into the debugger. If we try to // find the document in the "CurrentSolution" then when we try to get the semantic // model below then it might take a *long* time as all dependent compilations are built. var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); SyntaxNode memberDecl = token.GetAncestor<MemberDeclarationSyntax>(); // field or event field declarations may contain multiple variable declarators. Try finding the correct one. // If the position does not point to one, try using the first one. if (memberDecl != null && (memberDecl.Kind() == SyntaxKind.FieldDeclaration || memberDecl.Kind() == SyntaxKind.EventFieldDeclaration)) { SeparatedSyntaxList<VariableDeclaratorSyntax> variableDeclarators = ((BaseFieldDeclarationSyntax)memberDecl).Declaration.Variables; foreach (var declarator in variableDeclarators) { if (declarator.FullSpan.Contains(token.FullSpan)) { memberDecl = declarator; break; } } if (memberDecl == null) { memberDecl = variableDeclarators.Count > 0 ? variableDeclarators[0] : null; } } if (memberDecl != null) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var memberSymbol = semanticModel.GetDeclaredSymbol(memberDecl, cancellationToken); if (memberSymbol != null) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var lineNumber = text.Lines.GetLineFromPosition(position).LineNumber; var accessor = token.GetAncestor<AccessorDeclarationSyntax>(); var memberLine = accessor == null ? text.Lines.GetLineFromPosition(memberDecl.SpanStart).LineNumber : text.Lines.GetLineFromPosition(accessor.SpanStart).LineNumber; name = memberSymbol.ToDisplayString(s_nameFormat); lineOffset = lineNumber - memberLine; return new DebugLocationInfo(name, lineOffset); } } return default(DebugLocationInfo); }
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)); }
public async Task<IList<string>> DoAsync( Document document, int position, string locationName, CancellationToken cancellationToken) { var result = SpecializedCollections.EmptyList<string>(); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var snapshot = text.FindCorrespondingEditorTextSnapshot(); locationName = locationName ?? string.Empty; // Get the prior values we've computed. var locationToExpressionsMap = snapshot != null ? _snapshotToExpressions.GetValue(snapshot, _ => new Dictionary<string, LinkedList<IList<string>>>()) : new Dictionary<string, LinkedList<IList<string>>>(); var cachedExpressionLists = locationToExpressionsMap.GetOrAdd(locationName, _ => new LinkedList<IList<string>>()); // Determine the right expressions for this position. var expressions = await _proximityExpressionsGetter.GetProximityExpressionsAsync(document, position, cancellationToken).ConfigureAwait(false); // If we get a new set of expressions, then add it to the list and evict any values we // no longer need. if (expressions != null) { if (cachedExpressionLists.Count == 0 || !cachedExpressionLists.First.Value.SetEquals(expressions)) { cachedExpressionLists.AddFirst(expressions); while (cachedExpressionLists.Count > MaxCacheLength) { cachedExpressionLists.RemoveLast(); } } } // Return all the unique values from the previous and current invocation. However, if // these are not the current values, then pull out any expressions that are not valid in // our current context. if (cachedExpressionLists.Any()) { var list = new List<string>(); foreach (var expr in cachedExpressionLists.Flatten()) { if (await _proximityExpressionsGetter.IsValidAsync(document, position, expr, cancellationToken).ConfigureAwait(false)) { list.Add(expr); } } result = list.Distinct().ToList(); } return result; }
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); }
public async Task<IEnumerable<CompletionItemGroup>> GetGroupsAsync( Document document, int position, CompletionTriggerInfo triggerInfo, IEnumerable<ICompletionProvider> completionProviders, CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return await GetGroupsAsync(document, text, position, triggerInfo, completionProviders, document.Project.Solution.Workspace.Options, cancellationToken).ConfigureAwait(false); }
internal static async Task<DebugLocationInfo> GetInfoAsync(Document document, int position, CancellationToken cancellationToken) { // PERF: This method will be called synchronously on the UI thread for every breakpoint in the solution. // Therefore, it is important that we make this call as cheap as possible. Rather than constructing a // containing Symbol and using ToDisplayString (which might be more *correct*), we'll just do the best we // can with Syntax. This approach is capable of providing parity with the pre-Roslyn implementation. var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); var syntaxFactsService = document.Project.LanguageServices.GetService<ISyntaxFactsService>(); var memberDeclaration = syntaxFactsService.GetContainingMemberDeclaration(root, position, useFullSpan: true); // It might be reasonable to return an empty Name and a LineOffset from the beginning of the // file for GlobalStatements. However, the only known caller (Breakpoints Window) doesn't // appear to consume this information, so we'll just return the simplest thing (no location). if ((memberDeclaration == null) || (memberDeclaration.Kind() == SyntaxKind.GlobalStatement)) { return default(DebugLocationInfo); } // field or event field declarations may contain multiple variable declarators. Try finding the correct one. // If the position does not point to one, try using the first one. VariableDeclaratorSyntax fieldDeclarator = null; if (memberDeclaration.Kind() == SyntaxKind.FieldDeclaration || memberDeclaration.Kind() == SyntaxKind.EventFieldDeclaration) { SeparatedSyntaxList<VariableDeclaratorSyntax> variableDeclarators = ((BaseFieldDeclarationSyntax)memberDeclaration).Declaration.Variables; foreach (var declarator in variableDeclarators) { if (declarator.FullSpan.Contains(position)) { fieldDeclarator = declarator; break; } } if (fieldDeclarator == null) { fieldDeclarator = variableDeclarators.Count > 0 ? variableDeclarators[0] : null; } } var name = syntaxFactsService.GetDisplayName(fieldDeclarator ?? memberDeclaration, DisplayNameOptions.IncludeNamespaces | DisplayNameOptions.IncludeParameters); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var lineNumber = text.Lines.GetLineFromPosition(position).LineNumber; var accessor = memberDeclaration.GetAncestorOrThis<AccessorDeclarationSyntax>(); var memberLine = text.Lines.GetLineFromPosition(accessor?.SpanStart ?? memberDeclaration.SpanStart).LineNumber; var lineOffset = lineNumber - memberLine; return new DebugLocationInfo(name, lineOffset); }
protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); // first try to get the #r string literal token. If we couldn't, then we're not in a #r // reference directive and we immediately bail. SyntaxToken stringLiteral; if (!TryGetStringLiteralToken(tree, position, out stringLiteral, cancellationToken)) { return null; } var documentPath = document.Project.IsSubmission ? null : document.FilePath; var textChangeSpan = this.GetTextChangeSpan(stringLiteral, position); var gacHelper = new GlobalAssemblyCacheCompletionHelper(this, textChangeSpan, itemRules: ItemRules.Instance); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var snapshot = text.FindCorrespondingEditorTextSnapshot(); if (snapshot == null) { // Passing null to GetFileSystemDiscoveryService raises an exception. // Instead, return here since there is no longer snapshot for this document. return null; } var assemblyReferenceResolver = document.Project.CompilationOptions.MetadataReferenceResolver as AssemblyReferenceResolver; if (assemblyReferenceResolver == null) { return null; } var metadataFileResolver = assemblyReferenceResolver.PathResolver as MetadataFileReferenceResolver; if (metadataFileResolver == null) { return null; } var fileSystemHelper = new FileSystemCompletionHelper( this, textChangeSpan, GetFileSystemDiscoveryService(snapshot), Glyph.OpenFolder, Glyph.Assembly, searchPaths: metadataFileResolver.SearchPaths, allowableExtensions: new[] { ".dll", ".exe" }, exclude: path => path.Contains(","), itemRules: ItemRules.Instance); var pathThroughLastSlash = this.GetPathThroughLastSlash(stringLiteral, position); return gacHelper.GetItems(pathThroughLastSlash, documentPath).Concat( fileSystemHelper.GetItems(pathThroughLastSlash, documentPath)); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var indentationOptions = IndentationOptions.FromDocument(document); var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var violatingTrivia = syntaxRoot.FindTrivia(diagnostic.Location.SourceSpan.Start); var stringBuilder = new StringBuilder(); int firstTriviaIndex = violatingTrivia.GetLineSpan().StartLinePosition.Character; string relevantText; if (firstTriviaIndex == 0) { relevantText = violatingTrivia.ToFullString(); } else { SourceText sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); relevantText = sourceText.ToString(new TextSpan(violatingTrivia.FullSpan.Start - firstTriviaIndex, firstTriviaIndex + violatingTrivia.FullSpan.Length)); } int column = 0; for (int i = 0; i < relevantText.Length; i++) { char c = relevantText[i]; if (c == '\t') { var offsetWithinTabColumn = column % indentationOptions.TabSize; var spaceCount = indentationOptions.TabSize - offsetWithinTabColumn; if (i >= firstTriviaIndex) { stringBuilder.Append(' ', spaceCount); } column += spaceCount; } else { if (i >= firstTriviaIndex) { stringBuilder.Append(c); } column++; } } var newSyntaxRoot = syntaxRoot.ReplaceTrivia(violatingTrivia, SyntaxFactory.Whitespace(stringBuilder.ToString())); return document.WithSyntaxRoot(newSyntaxRoot); }
internal static async Task<Solution> GetTransformedSolutionAsync(Document document, CancellationToken cancellationToken) { SourceText text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); string actualSourceText = text.ToString(); text = SourceText.From(actualSourceText, Encoding.UTF8); // Changing the encoding as part of a "normal" text change does not work. // Roslyn will not see an encoding change as a text change and assumes that // there is nothing to do. Solution solutionWithoutDocument = document.Project.Solution.RemoveDocument(document.Id); return solutionWithoutDocument.AddDocument(DocumentId.CreateNewId(document.Project.Id), document.Name, text, document.Folders, document.FilePath); }
protected override async Task<CompletionItem> GetBuilderAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken)) { if (triggerInfo.TriggerReason == CompletionTriggerReason.TypeCharCommand) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); if (triggerInfo.IsDebugger) { // Aggressive Intellisense in the debugger: always show the builder return CreateEmptyBuilder(text, position); } var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = tree .FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position); if (token.Kind() == SyntaxKind.None) { return null; } var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false); var typeInferrer = document.GetLanguageService<ITypeInferenceService>(); if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken)) { return CreateBuilder(text, position, CSharpFeaturesResources.LambdaExpression, CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration); } else if (IsAnonymousObjectCreation(token)) { return CreateBuilder(text, position, CSharpFeaturesResources.MemberName, CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation); } else if (token.IsPreProcessorExpressionContext()) { return CreateEmptyBuilder(text, position); } else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken)) { return CreateBuilder(text, position, CSharpFeaturesResources.ImplicitArrayCreation, CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray); } else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword)) { return CreateBuilder(text, position, CSharpFeaturesResources.RangeVariable, CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl); } } return null; }
private static async Task<CodeFixContext?> GetCodeFixContext(Document originalDocument, ICodeActionRequest request, List<CodeAction> actionsDestination) { var sourceText = await originalDocument.GetTextAsync(); var semanticModel = await originalDocument.GetSemanticModelAsync(); var diagnostics = semanticModel.GetDiagnostics(); var location = GetTextSpan(request, sourceText); var pointDiagnostics = diagnostics.Where(d => d.Location.SourceSpan.Contains(location)).ToImmutableArray(); if (pointDiagnostics.Any()) { return new CodeFixContext(originalDocument, pointDiagnostics.First().Location.SourceSpan, pointDiagnostics, (a, d) => actionsDestination.Add(a), CancellationToken.None); } return null; }
public void UpdateView(Document document, SpanChange spanSource) { var documentText = document.GetTextAsync().Result.ToString(); if (TextView.TextBuffer.CurrentSnapshot.GetText() != documentText) { SourceTextContainer container; Document documentBackedByTextBuffer; UpdateBuffer(document, spanSource, out container, out documentBackedByTextBuffer); } // Picking a different span: no text change; update span anyway. SpanToShow = spanSource.GetSpan(); var spanInBuffer = new SnapshotSpan(TextView.TextBuffer.CurrentSnapshot, new Span(SpanToShow.Start, 0)); TextView.ViewScroller.EnsureSpanVisible(spanInBuffer, EnsureSpanVisibleOptions.None); Tagger.OnTextBufferChanged(); }
static async Task<long> GetDocumentSizeAsync (Document document, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested (); if (document == null) return 0; var result = GetFileSize (document.FilePath); if (result >= 0) { return result; } // not a physical file, in that case, use text as a fallback. var text = await document.GetTextAsync (CancellationToken.None).ConfigureAwait (false); return text.Length; }
private void AnalyzeSourceFile(Document sourceFile) { var root = (SyntaxNode)sourceFile.GetSyntaxRootAsync().Result; var semanticModel = (SemanticModel)sourceFile.GetSemanticModelAsync().Result; var sloc = sourceFile.GetTextAsync().Result.Lines.Count; try { PerformAnalysisTypes(sourceFile, root, semanticModel); SLOC += sloc; } catch (InvalidProjectFileException ex) { Logs.ErrorLog.Info("SourceFile is not analyzed: {0}: Reason: {1}", sourceFile.FilePath, ex.Message); } }
public static async Task<IEnumerable<LinePositionSpanTextChange>> Convert(Document document, IEnumerable<TextChange> changes) { var text = await document.GetTextAsync(); return changes .OrderByDescending(change => change.Span) .Select(change => { var span = change.Span; var newText = change.NewText; var prefix = string.Empty; var postfix = string.Empty; if (newText.Length > 0) { // Roslyn computes text changes on character arrays. So it might happen that a // change starts inbetween \r\n which is OK when you are offset-based but a problem // when you are line,column-based. This code extends text edits which just overlap // a with a line break to its full line break if (span.Start > 0 && newText[0] == '\n' && text[span.Start - 1] == '\r') { // text: foo\r\nbar\r\nfoo // edit: [----) span = TextSpan.FromBounds(span.Start - 1, span.End); prefix = "\r"; } if (span.End < text.Length - 1 && newText[newText.Length - 1] == '\r' && text[span.End] == '\n') { // text: foo\r\nbar\r\nfoo // edit: [----) span = TextSpan.FromBounds(span.Start, span.End + 1); postfix = "\n"; } } var linePositionSpan = text.Lines.GetLinePositionSpan(span); return new LinePositionSpanTextChange() { NewText = prefix + newText + postfix, StartLine = linePositionSpan.Start.Line + 1, StartColumn = linePositionSpan.Start.Character + 1, EndLine = linePositionSpan.End.Line + 1, EndColumn = linePositionSpan.End.Character + 1 }; }); }
protected override async Task<CompletionItem> GetSuggestionModeItemAsync(Document document, int position, TextSpan itemSpan, CompletionTrigger trigger, CancellationToken cancellationToken = default(CancellationToken)) { if (trigger.Kind == CompletionTriggerKind.Insertion) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = tree .FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position); if (token.Kind() == SyntaxKind.None) { return null; } var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false); var typeInferrer = document.GetLanguageService<ITypeInferenceService>(); if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken)) { return CreateSuggestionModeItem(CSharpFeaturesResources.LambdaExpression, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration); } else if (IsAnonymousObjectCreation(token) || IsPossibleTupleExpression(token)) { return CreateSuggestionModeItem(CSharpFeaturesResources.MemberName, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation); } else if (token.IsPreProcessorExpressionContext()) { return CreateEmptySuggestionModeItem(itemSpan); } else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken)) { return CreateSuggestionModeItem(CSharpFeaturesResources.ImplicitArrayCreation, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray); } else if (token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword)) { return CreateSuggestionModeItem(CSharpFeaturesResources.RangeVariable, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl); } else if (tree.IsNamespaceDeclarationNameContext(position, cancellationToken)) { return CreateSuggestionModeItem(CSharpFeaturesResources.NamespaceName, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToNamespaceDeclaration); } } return null; }
private async Task<Solution> ChangeDocumentNameAsync(Document document, ClassDeclarationSyntax classDeclaration, CancellationToken cancellationToken) { DocumentId newDocumentId = DocumentId.CreateNewId(document.Project.Id); Solution newSolution = document.Project.Solution; newSolution = newSolution.AddDocument( documentId: newDocumentId, name: classDeclaration.Identifier.ValueText, text: await document.GetTextAsync(), folders: document.Folders ); newSolution = newSolution.RemoveDocument( documentId: document.Id ); return newSolution; }
public static async Task<IEnumerable<LinePositionSpanTextChange>> Convert(Document document, IEnumerable<TextChange> changes) { var lines = (await document.GetTextAsync()).Lines; return changes .OrderByDescending(change => change.Span) .Select(change => { var linePositionSpan = lines.GetLinePositionSpan(change.Span); return new LinePositionSpanTextChange() { NewText = change.NewText, StartLine = linePositionSpan.Start.Line + 1, StartColumn = linePositionSpan.Start.Character + 1, EndLine = linePositionSpan.End.Line + 1, EndColumn = linePositionSpan.End.Character + 1 }; }); }
protected override void VisitDocument(Document document, SyntaxNode root) { var sloc = document.GetTextAsync().Result.Lines.Count; if (Result.CurrentAnalyzedProjectType == Enums.ProjectType.WP7) Result.generalResults.SLOCWP7 += sloc; else Result.generalResults.SLOCWP8 += sloc; CSharpSyntaxWalker walker; SemanticModel semanticModel = (SemanticModel)document.GetSemanticModelAsync().Result; if (bool.Parse(ConfigurationManager.AppSettings["IsGeneralAsyncDetectionEnabled"])) { walker = new GeneralAsyncDetectionWalker { Result = Result, SemanticModel = semanticModel, Document = document }; walker.Visit(root); } if (bool.Parse(ConfigurationManager.AppSettings["IsAsyncUsageDetectionEnabled"])) { walker = new AsyncUsageDetectionWalker { Result = Result, SemanticModel = semanticModel, Document = document, IsEventHandlerWalkerEnabled = false }; walker.Visit(root); } if (bool.Parse(ConfigurationManager.AppSettings["IsSyncUsageDetectionEnabled"])) { walker = new SyncUsageDetectionWalker { Result = Result, SemanticModel = semanticModel, Document = document }; walker.Visit(root); } if (bool.Parse(ConfigurationManager.AppSettings["IsAPMDiagnosisDetectionEnabled"])) { walker = new APMDiagnosisDetectionWalker { Result = Result, SemanticModel = semanticModel, Document = document }; walker.Visit(root); } if (bool.Parse(ConfigurationManager.AppSettings["IsAsyncAwaitDetectionEnabled"])) { walker = new AsyncAwaitDetectionWalker { Result = Result, SemanticModel = semanticModel, Document = document, AnalyzedMethods = AnalyzedMethods }; walker.Visit(root); } if (bool.Parse(ConfigurationManager.AppSettings["DispatcherDetectionEnabled"])) { walker = new DispatcherDetectionWalker { Result = Result, SemanticModel = semanticModel, Document = document, AnalyzedMethods = AnalyzedMethodsDict }; walker.Visit(root); } }
private async Task <InvocationContext> GetInvocation(Microsoft.CodeAnalysis.Document document, int offset) { var sourceText = await document.GetTextAsync(); var position = offset; var tree = await document.GetSyntaxTreeAsync(); var root = await tree.GetRootAsync(); var node = root.FindToken(position).Parent; // Walk up until we find a node that we're interested in. while (node != null) { if (node is InvocationExpressionSyntax invocation && invocation.ArgumentList != null && invocation.ArgumentList.Span.Contains(position)) { var semanticModel = await document.GetSemanticModelAsync(); return(new InvocationContext(semanticModel, position, invocation.Expression, invocation.ArgumentList, invocation.IsInStaticContext())); } if (node is ObjectCreationExpressionSyntax objectCreation && objectCreation.ArgumentList != null && objectCreation.ArgumentList.Span.Contains(position)) { var semanticModel = await document.GetSemanticModelAsync(); return(new InvocationContext(semanticModel, position, objectCreation, objectCreation.ArgumentList, objectCreation.IsInStaticContext())); } if (node is AttributeSyntax attributeSyntax && attributeSyntax.ArgumentList != null && attributeSyntax.ArgumentList.Span.Contains(position)) { var semanticModel = await document.GetSemanticModelAsync(); return(new InvocationContext(semanticModel, position, attributeSyntax, attributeSyntax.ArgumentList, attributeSyntax.IsInStaticContext())); } node = node.Parent; } return(null); }
/// <summary> /// Trims leading and trailing whitespace from <paramref name="span"/>. /// </summary> /// <remarks> /// Returns unchanged <paramref name="span"/> in case <see cref="TextSpan.IsEmpty"/>. /// Returns empty Span with original <see cref="TextSpan.Start"/> in case it contains only whitespace. /// </remarks> public static async Task <TextSpan> GetTrimmedTextSpan(Document document, TextSpan span, CancellationToken cancellationToken) { if (span.IsEmpty) { return(span); } var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var start = span.Start; var end = span.End; while (start < end && char.IsWhiteSpace(sourceText[end - 1])) { end--; } while (start < end && char.IsWhiteSpace(sourceText[start])) { start++; } return(TextSpan.FromBounds(start, end)); }
/// <summary> /// Get the text changes between this document and a prior version of the same document. /// The changes, when applied to the text of the old document, will produce the text of the current document. /// </summary> public async Task <IEnumerable <TextChange> > GetTextChangesAsync(Document oldDocument, CancellationToken cancellationToken = default) { try { using (Logger.LogBlock(FunctionId.Workspace_Document_GetTextChanges, this.Name, cancellationToken)) { if (oldDocument == this) { // no changes return(SpecializedCollections.EmptyEnumerable <TextChange>()); } if (this.Id != oldDocument.Id) { throw new ArgumentException(WorkspacesResources.The_specified_document_is_not_a_version_of_this_document); } // first try to see if text already knows its changes IList <TextChange> textChanges = null; if (this.TryGetText(out var text) && oldDocument.TryGetText(out var oldText)) { if (text == oldText) { return(SpecializedCollections.EmptyEnumerable <TextChange>()); } var container = text.Container; if (container != null) { textChanges = text.GetTextChanges(oldText).ToList(); // if changes are significant (not the whole document being replaced) then use these changes if (textChanges.Count > 1 || (textChanges.Count == 1 && textChanges[0].Span != new TextSpan(0, oldText.Length))) { return(textChanges); } } } // get changes by diffing the trees if (this.SupportsSyntaxTree) { var tree = await this.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); return(tree.GetChanges(oldTree)); } text = await this.GetTextAsync(cancellationToken).ConfigureAwait(false); oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); return(text.GetTextChanges(oldText).ToList()); } } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private static async Task <O.TextPart[][]> CreateDocumentLines(R.Document document, ImmutableArray <R.Diagnostic> diagnostics) { var tree = await document.GetSyntaxTreeAsync().ConfigureAwait(false); var text = await document.GetTextAsync().ConfigureAwait(false); return(text.Lines .Select(x => { // TODO: diagnostics に該当するものがないなら LinkedList 使わないで行きたい気持ち var parts = new LinkedList <WorkingTextPart>(); // TODO: シンタックスハイライト parts.AddFirst(new WorkingTextPart(O.TextPartType.Plain, x.Span, null)); foreach (var diagnostic in diagnostics) { if (diagnostic.Location.SourceTree != tree) { continue; } var diagSpan = diagnostic.Location.SourceSpan; if (!x.Span.IntersectsWith(diagSpan)) { continue; } var node = parts.First; while (node != null) { var part = node.Value; if ((!part.Severity.HasValue || part.Severity.Value < diagnostic.Severity) && part.Span.Intersection(diagSpan) is R.Text.TextSpan intersection) { if (intersection.Start > part.Span.Start) { parts.AddBefore( node, new WorkingTextPart( part.Type, new R.Text.TextSpan(part.Span.Start, intersection.Start - part.Span.Start), part.Severity ) ); } node.Value = new WorkingTextPart(part.Type, intersection, diagnostic.Severity); if (intersection.End < part.Span.End) { node = parts.AddAfter( node, new WorkingTextPart( part.Type, new R.Text.TextSpan(intersection.End, part.Span.End - intersection.End), part.Severity ) ); } } node = node.Next; } } return parts .Select(y => new O.TextPart(y.Type, text.ToString(y.Span), y.Severity)) .ToArray(); }) .ToArray()); }
private static async Task <O.ChangedLineMap[]> CreateChangedLineMaps(R.Document oldDocument, R.Document newDocument) { var changes = await newDocument.GetTextChangesAsync(oldDocument).ConfigureAwait(false); var oldText = await oldDocument.GetTextAsync().ConfigureAwait(false); var lineChanges = new List <LineChange>(); foreach (var change in changes) { var startLine = oldText.Lines.IndexOf(change.Span.Start); var oldLineCount = oldText.ToString(change.Span).Count(c => c == '\n') + 1; var endLine = startLine + oldLineCount; var additionalLineCount = change.NewText.Count(c => c == '\n') + 1 - oldLineCount; // 近いものがあるならマージしていく var isMerged = false; for (var i = 0; i < lineChanges.Count; i++) { var lc = lineChanges[i]; // change // lc // みたいな配置になっている場合 var b1 = startLine <= lc.StartLine && startLine + oldLineCount >= lc.StartLine; // lc // change var b2 = lc.StartLine <= startLine && lc.StartLine + lc.OldLineCount >= startLine; isMerged = b1 || b2; if (isMerged) { var newStartLine = Math.Min(startLine, lc.StartLine); lineChanges[i] = new LineChange( newStartLine, Math.Max(endLine, lc.StartLine + lc.OldLineCount) - newStartLine, lc.AdditionalLineCount + additionalLineCount ); break; } } if (!isMerged) { lineChanges.Add(new LineChange(startLine, oldLineCount, additionalLineCount)); } } // StartLine 順に並べて、変更後の行数を反映しながら結果を詰めていく lineChanges.Sort((x, y) => x.StartLine.CompareTo(y.StartLine)); var changedLineMaps = new O.ChangedLineMap[lineChanges.Count]; var additional = 0; for (var i = 0; i < changedLineMaps.Length; i++) { var lc = lineChanges[i]; changedLineMaps[i] = new O.ChangedLineMap( new O.LineRange(lc.StartLine, lc.OldLineCount), new O.LineRange(lc.StartLine + additional, lc.OldLineCount + lc.AdditionalLineCount) ); additional += lc.AdditionalLineCount; } return(changedLineMaps); }
private static async Task <List <TextChange> > AddDocumentMergeChangesAsync( Document oldDocument, Document newDocument, List <TextChange> cumulativeChanges, List <UnmergedDocumentChanges> unmergedChanges, LinkedFileGroupSessionInfo groupSessionInfo, CancellationToken cancellationToken) { var unmergedDocumentChanges = new List <TextChange>(); var successfullyMergedChanges = new List <TextChange>(); int cumulativeChangeIndex = 0; foreach (var change in await newDocument.GetTextChangesAsync(oldDocument).ConfigureAwait(false)) { while (cumulativeChangeIndex < cumulativeChanges.Count && cumulativeChanges[cumulativeChangeIndex].Span.End < change.Span.Start) { // Existing change that does not overlap with the current change in consideration successfullyMergedChanges.Add(cumulativeChanges[cumulativeChangeIndex]); cumulativeChangeIndex++; groupSessionInfo.IsolatedDiffs++; } if (cumulativeChangeIndex < cumulativeChanges.Count) { var cumulativeChange = cumulativeChanges[cumulativeChangeIndex]; if (!cumulativeChange.Span.IntersectsWith(change.Span)) { // The current change in consideration does not intersect with any existing change successfullyMergedChanges.Add(change); groupSessionInfo.IsolatedDiffs++; } else { if (change.Span != cumulativeChange.Span || change.NewText != cumulativeChange.NewText) { // The current change in consideration overlaps an existing change but // the changes are not identical. unmergedDocumentChanges.Add(change); groupSessionInfo.OverlappingDistinctDiffs++; if (change.Span == cumulativeChange.Span) { groupSessionInfo.OverlappingDistinctDiffsWithSameSpan++; if (change.NewText.Contains(cumulativeChange.NewText) || cumulativeChange.NewText.Contains(change.NewText)) { groupSessionInfo.OverlappingDistinctDiffsWithSameSpanAndSubstringRelation++; } } } else { // The current change in consideration is identical to an existing change successfullyMergedChanges.Add(change); cumulativeChangeIndex++; groupSessionInfo.IdenticalDiffs++; } } } else { // The current change in consideration does not intersect with any existing change successfullyMergedChanges.Add(change); groupSessionInfo.IsolatedDiffs++; } } while (cumulativeChangeIndex < cumulativeChanges.Count) { // Existing change that does not overlap with the current change in consideration successfullyMergedChanges.Add(cumulativeChanges[cumulativeChangeIndex]); cumulativeChangeIndex++; groupSessionInfo.IsolatedDiffs++; } if (unmergedDocumentChanges.Any()) { unmergedChanges.Add(new UnmergedDocumentChanges( unmergedDocumentChanges.AsEnumerable(), await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false), oldDocument.Project.Name)); } return(successfullyMergedChanges); }