Beispiel #1
0
        /// <summary>
        /// Enables editing the definition of one of the symbol's declarations.
        /// Partial types and methods may have more than one declaration.
        /// </summary>
        /// <param name="symbol">The symbol to edit.</param>
        /// <param name="editAction">The action that makes edits to the declaration.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/>.</param>
        /// <returns>The new symbol including the changes.</returns>
        public async Task <ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default)
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);

            CheckSymbolArgument(currentSymbol, symbol);
            if (TryGetBestDeclarationForSingleEdit(currentSymbol, out var declaration))
            {
                return(await this.EditDeclarationAsync(currentSymbol, declaration, editAction, cancellationToken).ConfigureAwait(false));
            }

            return(null);
        }
Beispiel #2
0
        public async Task <ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            ISymbol member,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default
            )
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken)
                                .ConfigureAwait(false);

            CheckSymbolArgument(currentSymbol, symbol);

            var currentMember = await this.GetCurrentSymbolAsync(member, cancellationToken)
                                .ConfigureAwait(false);

            CheckSymbolArgument(currentMember, member);

            // get first symbol declaration that encompasses at least one of the member declarations
            var memberDecls = this.GetDeclarations(currentMember).ToList();
            var declaration = this.GetDeclarations(currentSymbol)
                              .FirstOrDefault(
                d =>
                memberDecls.Any(
                    md =>
                    md.SyntaxTree == d.SyntaxTree &&
                    d.FullSpan.IntersectsWith(md.FullSpan)
                    )
                );

            if (declaration == null)
            {
                throw new ArgumentException(
                          string.Format(
                              WorkspacesResources.The_member_0_is_not_declared_within_the_declaration_of_the_symbol,
                              member.Name
                              )
                          );
            }

            return(await this.EditDeclarationAsync(
                       currentSymbol,
                       declaration,
                       editAction,
                       cancellationToken
                       )
                   .ConfigureAwait(false));
        }
Beispiel #3
0
        public Task <ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            Location location,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default)
        {
            var sourceTree = location.SourceTree;

            var doc = _currentSolution.GetDocument(sourceTree) ?? _originalSolution.GetDocument(sourceTree);

            if (doc != null)
            {
                return(EditOneDeclarationAsync(symbol, doc.Id, location.SourceSpan.Start, editAction, cancellationToken));
            }

            throw new ArgumentException("The location specified is not part of the solution.", nameof(location));
        }
Beispiel #4
0
        private async Task <ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            DocumentId documentId,
            int position,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default
            )
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken)
                                .ConfigureAwait(false);

            CheckSymbolArgument(currentSymbol, symbol);

            var decl = this.GetDeclarations(currentSymbol)
                       .FirstOrDefault(
                d =>
            {
                var doc = _currentSolution.GetDocument(d.SyntaxTree);
                return(doc != null &&
                       doc.Id == documentId &&
                       d.FullSpan.IntersectsWith(position));
            }
                );

            if (decl == null)
            {
                throw new ArgumentNullException(
                          WorkspacesResources.The_position_is_not_within_the_symbol_s_declaration,
                          nameof(position)
                          );
            }

            return(await this.EditDeclarationAsync(
                       currentSymbol,
                       decl,
                       editAction,
                       cancellationToken
                       )
                   .ConfigureAwait(false));
        }
Beispiel #5
0
        private async Task <ISymbol> EditDeclarationAsync(
            ISymbol currentSymbol,
            SyntaxNode declaration,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken
            )
        {
            var doc    = _currentSolution.GetDocument(declaration.SyntaxTree);
            var editor = await DocumentEditor
                         .CreateAsync(doc, cancellationToken)
                         .ConfigureAwait(false);

            editor.TrackNode(declaration);
            await editAction(editor, declaration, cancellationToken).ConfigureAwait(false);

            var newDoc = editor.GetChangedDocument();

            _currentSolution = newDoc.Project.Solution;

            // try to find new symbol by looking up via original declaration
            var model = await newDoc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var newDeclaration = model.SyntaxTree
                                 .GetRoot(cancellationToken)
                                 .GetCurrentNode(declaration);

            if (newDeclaration != null)
            {
                var newSymbol = model.GetDeclaredSymbol(newDeclaration, cancellationToken);
                if (newSymbol != null)
                {
                    return(newSymbol);
                }
            }

            // otherwise fallback to rebinding with original symbol
            return(await this.GetCurrentSymbolAsync(currentSymbol, cancellationToken)
                   .ConfigureAwait(false));
        }
Beispiel #6
0
        /// <summary>
        /// Enables editing all the symbol's declarations. 
        /// Partial types and methods may have more than one declaration.
        /// </summary>
        /// <param name="symbol">The symbol to be edited.</param>
        /// <param name="editAction">The action that makes edits to the declaration.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/>.</param>
        /// <returns>The new symbol including the changes.</returns>
        public async Task<ISymbol> EditAllDeclarationsAsync(
            ISymbol symbol,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);
            CheckSymbolArgument(currentSymbol, symbol);

            var declsByDocId = this.GetDeclarations(currentSymbol).ToLookup(d => _currentSolution.GetDocument(d.SyntaxTree).Id);

            var solutionEditor = new SolutionEditor(_currentSolution);

            foreach (var declGroup in declsByDocId)
            {
                var docId = declGroup.Key;
                var editor = await solutionEditor.GetDocumentEditorAsync(docId, cancellationToken).ConfigureAwait(false);

                foreach (var decl in declGroup)
                {
                    editor.TrackNode(decl); // ensure the declaration gets tracked
                    await editAction(editor, decl, cancellationToken).ConfigureAwait(false);
                }
            }

            _currentSolution = solutionEditor.GetChangedSolution();

            // try to find new symbol by looking up via original declarations
            foreach (var declGroup in declsByDocId)
            {
                var doc = _currentSolution.GetDocument(declGroup.Key);
                var model = await doc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                foreach (var decl in declGroup)
                {
                    var newDeclaration = model.SyntaxTree.GetRoot(cancellationToken).GetCurrentNode(decl);
                    if (newDeclaration != null)
                    {
                        var newSymbol = model.GetDeclaredSymbol(newDeclaration);
                        if (newSymbol != null)
                        {
                            return newSymbol;
                        }
                    }
                }
            }

            // otherwise fallback to rebinding with original symbol
            return await GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);
        }
Beispiel #7
0
        /// <summary>
        /// Enables editing the symbol's declaration where the member is also declared.
        /// Partial types and methods may have more than one declaration.
        /// </summary>
        /// <param name="symbol">The symbol to edit.</param>
        /// <param name="member">A symbol whose declaration is contained within one of the primary symbol's declarations.</param>
        /// <param name="editAction">The action that makes edits to the declaration.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/>.</param>
        /// <returns>The new symbol including the changes.</returns>
        public async Task<ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            ISymbol member,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);
            CheckSymbolArgument(currentSymbol, symbol);

            var currentMember = await this.GetCurrentSymbolAsync(member, cancellationToken).ConfigureAwait(false);
            CheckSymbolArgument(currentMember, member);

            // get first symbol declaration that encompasses at least one of the member declarations
            var memberDecls = this.GetDeclarations(currentMember).ToList();
            var declaration = this.GetDeclarations(currentSymbol).FirstOrDefault(d => memberDecls.Any(md => md.SyntaxTree == d.SyntaxTree && d.FullSpan.IntersectsWith(md.FullSpan)));

            if (declaration == null)
            {
                throw new ArgumentException(string.Format(WorkspacesResources.The_member_0_is_not_declared_within_the_declaration_of_the_symbol, member.Name));
            }

            return await this.EditDeclarationAsync(currentSymbol, declaration, editAction, cancellationToken).ConfigureAwait(false);
        }
Beispiel #8
0
        private async Task<ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            DocumentId documentId,
            int position,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);
            CheckSymbolArgument(currentSymbol, symbol);

            var decl = this.GetDeclarations(currentSymbol).FirstOrDefault(d =>
            {
                var doc = _currentSolution.GetDocument(d.SyntaxTree);
                return doc != null && doc.Id == documentId && d.FullSpan.IntersectsWith(position);
            });

            if (decl == null)
            {
                throw new ArgumentNullException(WorkspacesResources.The_position_is_not_within_the_symbol_s_declaration, nameof(position));
            }

            return await this.EditDeclarationAsync(currentSymbol, decl, editAction, cancellationToken).ConfigureAwait(false);
        }
Beispiel #9
0
        /// <summary>
        /// Enables editing the definition of one of the symbol's declarations.
        /// Partial types and methods may have more than one declaration.
        /// </summary>
        /// <param name="symbol">The symbol to edit.</param>
        /// <param name="location">A location within one of the symbol's declarations.</param>
        /// <param name="editAction">The action that makes edits to the declaration.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/>.</param>
        /// <returns>The new symbol including the changes.</returns>
        public async Task<ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            Location location,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var sourceTree = location.SourceTree;

            var doc = _currentSolution.GetDocument(sourceTree);
            if (doc != null)
            {
                return await this.EditOneDeclarationAsync(symbol, doc.Id, location.SourceSpan.Start, editAction, cancellationToken).ConfigureAwait(false);
            }

            doc = _originalSolution.GetDocument(sourceTree);
            if (doc != null)
            {
                return await this.EditOneDeclarationAsync(symbol, doc.Id, location.SourceSpan.Start, editAction, cancellationToken).ConfigureAwait(false);
            }

            throw new ArgumentException("The location specified is not part of the solution.", nameof(location));
        }
Beispiel #10
0
        private async Task<ISymbol> EditDeclarationAsync(
            ISymbol currentSymbol,
            SyntaxNode declaration,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken)
        {
            var doc = _currentSolution.GetDocument(declaration.SyntaxTree);
            var editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false);

            editor.TrackNode(declaration);
            await editAction(editor, declaration, cancellationToken).ConfigureAwait(false);

            var newDoc = editor.GetChangedDocument();
            _currentSolution = newDoc.Project.Solution;

            // try to find new symbol by looking up via original declaration
            var model = await newDoc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
            var newDeclaration = model.SyntaxTree.GetRoot(cancellationToken).GetCurrentNode(declaration);
            if (newDeclaration != null)
            {
                var newSymbol = model.GetDeclaredSymbol(newDeclaration, cancellationToken);
                if (newSymbol != null)
                {
                    return newSymbol;
                }
            }

            // otherwise fallback to rebinding with original symbol
            return await this.GetCurrentSymbolAsync(currentSymbol, cancellationToken).ConfigureAwait(false);
        }
Beispiel #11
0
        /// <summary>
        /// Enables editing the definition of one of the symbol's declarations.
        /// Partial types and methods may have more than one declaration.
        /// </summary>
        /// <param name="symbol">The symbol to edit.</param>
        /// <param name="editAction">The action that makes edits to the declaration.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/>.</param>
        /// <returns>The new symbol including the changes.</returns>
        public async Task<ISymbol> EditOneDeclarationAsync(
            ISymbol symbol,
            AsyncDeclarationEditAction editAction,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);

            CheckSymbolArgument(currentSymbol, symbol);
            if (TryGetBestDeclarationForSingleEdit(currentSymbol, out var declaration))
            {
                return await this.EditDeclarationAsync(currentSymbol, declaration, editAction, cancellationToken).ConfigureAwait(false);
            }

            return null;
        }