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)));
        }
Exemplo n.º 3
0
        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);
 }
Exemplo n.º 6
0
        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>();
        }
Exemplo n.º 7
0
        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);
		}
Exemplo n.º 10
0
        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);
            }
        }
Exemplo n.º 11
0
        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);
 }
Exemplo n.º 16
0
 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);
 }
Exemplo n.º 17
0
        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;
        }
Exemplo n.º 22
0
        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;
        }
Exemplo n.º 23
0
        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;
		}
Exemplo n.º 25
0
        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;
        }
Exemplo n.º 28
0
        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;
        }
Exemplo n.º 29
0
        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
                    };
                });
        }
Exemplo n.º 30
0
        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);
            }
        }
Exemplo n.º 31
0
        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);
        }
Exemplo n.º 32
0
        /// <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));
        }
Exemplo n.º 33
0
        /// <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;
            }
        }
Exemplo n.º 34
0
        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());
        }
Exemplo n.º 35
0
        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);
        }
Exemplo n.º 36
0
            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);
            }