private static T RemoveNode <T>(
            T declaration,
            Func <T, SyntaxList <MemberDeclarationSyntax> > getMembers,
            int index,
            SyntaxRemoveOptions removeOptions) where T : SyntaxNode
        {
            SyntaxList <MemberDeclarationSyntax> members = getMembers(declaration);

            T newDeclaration = declaration.RemoveNode(members[index], removeOptions);

            if (index == 0 &&
                index < members.Count - 1)
            {
                members = getMembers(newDeclaration);

                MemberDeclarationSyntax nextMember = members[index];

                SyntaxTriviaList leadingTrivia = nextMember.GetLeadingTrivia();

                SyntaxTrivia trivia = leadingTrivia.FirstOrDefault();

                if (trivia.IsEndOfLineTrivia())
                {
                    MemberDeclarationSyntax newNextMember = nextMember.WithLeadingTrivia(leadingTrivia.RemoveAt(0));

                    newDeclaration = newDeclaration.ReplaceNode(nextMember, newNextMember);
                }
            }

            return(newDeclaration);
        }
        public static Task <Document> RefactorAsync(
            Document document,
            TypeParameterSyntax typeParameter,
            CancellationToken cancellationToken)
        {
            SyntaxNode node = typeParameter;

            var typeParameterList = (TypeParameterListSyntax)typeParameter.Parent;

            if (typeParameterList.Parameters.Count == 1)
            {
                node = typeParameterList;
            }

            SyntaxRemoveOptions options = SyntaxRemover.DefaultRemoveOptions;

            if (node.GetLeadingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                options &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (node.GetTrailingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                options &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(document.RemoveNodeAsync(node, options, cancellationToken));
        }
        internal static TRoot RemoveNodes <TRoot>(TRoot root,
                                                  IEnumerable <SyntaxNode> nodes,
                                                  SyntaxRemoveOptions options)
            where TRoot : SyntaxNode
        {
            if (nodes == null)
            {
                return(root);
            }

            var nodeArray = nodes.ToArray();

            if (nodeArray.Length == 0)
            {
                return(root);
            }

            var remover = new SyntaxRemover(nodes.ToArray(), options);
            var result  = remover.Visit(root);

            var residualTrivia = remover.ResidualTrivia;

            if (residualTrivia.Count > 0)
            {
                result = result.WithTrailingTrivia(result.GetTrailingTrivia().Concat(residualTrivia));
            }

            return((TRoot)result);
        }
 public SyntaxRemover(SyntaxNode[] nodes, SyntaxRemoveOptions options)
 {
     this._nodesToRemove  = new HashSet <SyntaxNode>(nodes);
     this._options        = options;
     this._searchSpan     = ComputeTotalSpan(nodes);
     this._residualTrivia = null;
 }
Exemple #5
0
 /// <summary>
 /// Creates a new tree of nodes with the specified node removed.
 /// </summary>
 /// <typeparam name="TRoot">The type of the root node.</typeparam>
 /// <param name="root">The root node from which to remove a descendant node from.</param>
 /// <param name="node">The node to remove.</param>
 /// <param name="options">Options that determine how the node's trivia is treated.</param>
 public static TRoot RemoveNode <TRoot>(this TRoot root,
                                        SyntaxNode node,
                                        SyntaxRemoveOptions options)
     where TRoot : SyntaxNode
 {
     return((TRoot)root.RemoveNodesCore(new[] { node }, options));
 }
Exemple #6
0
        public static Task <Document> RefactorAsync(
            Document document,
            BaseTypeSyntax baseType,
            CancellationToken cancellationToken)
        {
            SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

            if (baseType.GetLeadingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (baseType.GetTrailingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                var baseList = (BaseListSyntax)baseType.Parent;

                if (baseList.Types.IsLast(baseType) &&
                    !GenericSyntax.HasConstraintClauses(baseList.Parent))
                {
                    removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                }
            }

            return(document.RemoveNodeAsync(baseType, removeOptions, cancellationToken));
        }
Exemple #7
0
 /// <summary>
 /// Creates a new tree of nodes with the specified nodes removed.
 /// </summary>
 /// <typeparam name="TRoot">The type of the root node.</typeparam>
 /// <param name="root">The root node from which to remove a descendant node from.</param>
 /// <param name="nodes">The nodes to remove.</param>
 /// <param name="options">Options that determine how the nodes' trivia is treated.</param>
 public static TRoot RemoveNodes <TRoot>(
     this TRoot root,
     IEnumerable <SyntaxNode> nodes,
     SyntaxRemoveOptions options)
     where TRoot : SyntaxNode
 {
     return((TRoot)root.RemoveNodesCore(nodes, options));
 }
Exemple #8
0
 public SyntaxRemover(SyntaxNode[] nodesToRemove, SyntaxRemoveOptions options)
     : base(nodesToRemove.Any(n => n.IsPartOfStructuredTrivia()))
 {
     _nodesToRemove  = new HashSet <SyntaxNode>(nodesToRemove);
     _options        = options;
     _searchSpan     = ComputeTotalSpan(nodesToRemove);
     _residualTrivia = SyntaxTriviaListBuilder.Create();
 }
Exemple #9
0
 protected internal override SyntaxNode?RemoveNodesCore(
     IEnumerable <SyntaxNode> nodes,
     SyntaxRemoveOptions options
     )
 {
     return(SyntaxNodeRemover
            .RemoveNodes(this, nodes.Cast <CSharpSyntaxNode>(), options)
            .AsRootOfNewTreeWithOptionsFrom(this.SyntaxTree));
 }
        private static SyntaxNode RemoveEmptyNamespaces(SyntaxNode node, SyntaxRemoveOptions removeOptions)
        {
            IEnumerable <NamespaceDeclarationSyntax> emptyNamespaces = node
                                                                       .DescendantNodes()
                                                                       .Where(f => f.IsKind(SyntaxKind.NamespaceDeclaration))
                                                                       .Cast <NamespaceDeclarationSyntax>()
                                                                       .Where(f => !f.Members.Any());

            return(node.RemoveNodes(emptyNamespaces, removeOptions));
        }
Exemple #11
0
        /// <summary>
        /// Creates a new <see cref="StatementListInfo"/> with the specified node removed.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public StatementListInfo RemoveNode(SyntaxNode node, SyntaxRemoveOptions options)
        {
            ThrowInvalidOperationIfNotInitialized();

            SyntaxNode parent = Parent;

            if (parent.Kind() == SyntaxKind.Block)
            {
                return(new StatementListInfo(((BlockSyntax)parent).RemoveNode(node, options)));
            }

            return(new StatementListInfo(((SwitchSectionSyntax)parent).RemoveNode(node, options)));
        }
Exemple #12
0
        public StatementContainer RemoveNode(SyntaxNode node, SyntaxRemoveOptions options)
        {
            if (IsBlock)
            {
                return(new StatementContainer(Block.RemoveNode(node, options)));
            }

            if (IsSwitchSection)
            {
                return(new StatementContainer(SwitchSection.RemoveNode(node, options)));
            }

            return(this);
        }
Exemple #13
0
        public StatementsInfo RemoveNode(SyntaxNode node, SyntaxRemoveOptions options)
        {
            if (IsInBlock)
            {
                return(new StatementsInfo(Block.RemoveNode(node, options)));
            }

            if (IsInSwitchSection)
            {
                return(new StatementsInfo(SwitchSection.RemoveNode(node, options)));
            }

            return(this);
        }
Exemple #14
0
        public static SyntaxNode RemoveEmptyNamespaces(SyntaxNode node, SyntaxRemoveOptions removeOptions)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            IEnumerable <NamespaceDeclarationSyntax> emptyNamespaces = node
                                                                       .DescendantNodes()
                                                                       .Where(f => f.IsKind(SyntaxKind.NamespaceDeclaration))
                                                                       .Cast <NamespaceDeclarationSyntax>()
                                                                       .Where(f => !f.Members.Any());

            return(node.RemoveNodes(emptyNamespaces, removeOptions));
        }
Exemple #15
0
        public static Task<Document> RefactorAsync(
            Document document,
            ParameterSyntax parameter,
            CancellationToken cancellationToken)
        {
            SyntaxRemoveOptions options = RemoveHelper.DefaultRemoveOptions;

            if (parameter.GetLeadingTrivia().All(f => f.IsWhitespaceTrivia()))
                options &= ~SyntaxRemoveOptions.KeepLeadingTrivia;

            if (parameter.GetTrailingTrivia().All(f => f.IsWhitespaceTrivia()))
                options &= ~SyntaxRemoveOptions.KeepTrailingTrivia;

            return document.RemoveNodeAsync(parameter, options, cancellationToken);
        }
        public static SyntaxRemoveOptions GetRemoveOptions(CSharpSyntaxNode node)
        {
            SyntaxRemoveOptions removeOptions = DefaultRemoveOptions;

            if (node.GetLeadingTrivia().IsEmptyOrWhitespace())
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (node.GetTrailingTrivia().IsEmptyOrWhitespace())
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(removeOptions);
        }
Exemple #17
0
        private static SyntaxRemoveOptions GetMemberRemoveOptions(MemberDeclarationSyntax member)
        {
            SyntaxRemoveOptions removeOptions = DefaultMemberRemoveOptions;

            if (member.GetLeadingTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (member.GetTrailingTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(removeOptions);
        }
        internal static SyntaxRemoveOptions GetRemoveOptions(MemberDeclarationSyntax newMember)
        {
            SyntaxRemoveOptions removeOptions = DefaultRemoveOptions;

            if (newMember.GetLeadingTrivia().IsWhitespaceOrEndOfLine())
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (newMember.GetTrailingTrivia().IsWhitespaceOrEndOfLine())
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(removeOptions);
        }
Exemple #19
0
        private static SyntaxRemoveOptions GetRemoveOptions(StatementSyntax statement)
        {
            SyntaxRemoveOptions removeOptions = Remover.DefaultMemberRemoveOptions;

            if (statement.GetLeadingTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (statement.GetTrailingTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(removeOptions);
        }
Exemple #20
0
        public static SyntaxRemoveOptions GetRemoveOptions(CSharpSyntaxNode node)
        {
            SyntaxRemoveOptions removeOptions = DefaultRemoveOptions;

            if (node.GetLeadingTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (node.GetTrailingTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(removeOptions);
        }
        /// <summary>
        /// Creates a new <see cref="MemberDeclarationListInfo"/> with the specified node removed.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public MemberDeclarationListInfo RemoveNode(SyntaxNode node, SyntaxRemoveOptions options)
        {
            ThrowInvalidOperationIfNotInitialized();

            switch (Parent.Kind())
            {
            case SyntaxKind.CompilationUnit:
            {
                var compilationUnit = (CompilationUnitSyntax)Parent;
                compilationUnit = compilationUnit.RemoveNode(node, options);
                return(new MemberDeclarationListInfo(compilationUnit, compilationUnit.Members));
            }

            case SyntaxKind.NamespaceDeclaration:
            {
                var declaration = (NamespaceDeclarationSyntax)Parent;
                declaration = declaration.RemoveNode(node, options);
                return(new MemberDeclarationListInfo(declaration, declaration.Members));
            }

            case SyntaxKind.ClassDeclaration:
            {
                var declaration = (ClassDeclarationSyntax)Parent;
                declaration = declaration.RemoveNode(node, options);
                return(new MemberDeclarationListInfo(declaration, declaration.Members));
            }

            case SyntaxKind.StructDeclaration:
            {
                var declaration = (StructDeclarationSyntax)Parent;
                declaration = declaration.RemoveNode(node, options);
                return(new MemberDeclarationListInfo(declaration, declaration.Members));
            }

            case SyntaxKind.InterfaceDeclaration:
            {
                var declaration = (InterfaceDeclarationSyntax)Parent;
                declaration = declaration.RemoveNode(node, options);
                return(new MemberDeclarationListInfo(declaration, declaration.Members));
            }
            }

            throw new InvalidOperationException();
        }
Exemple #22
0
        public static Task <Document> RefactorAsync(
            Document document,
            BaseTypeSyntax baseType,
            CancellationToken cancellationToken)
        {
            SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

            if (baseType.GetLeadingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
            }

            if (baseType.GetTrailingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
            }

            return(document.RemoveNodeAsync(baseType, removeOptions, cancellationToken));
        }
Exemple #23
0
            internal static SyntaxRemoveOptions GetRemoveOptions(UsingDirectiveSyntax usingDirective)
            {
                SyntaxRemoveOptions removeOptions = SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepUnbalancedDirectives;

                if (!usingDirective.HasLeadingTrivia)
                {
                    removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
                }

                SyntaxTriviaList trailingTrivia = usingDirective.GetTrailingTrivia();

                if (trailingTrivia.Count == 1 &&
                    trailingTrivia.First().IsEndOfLineTrivia())
                {
                    removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                }

                return(removeOptions);
            }
Exemple #24
0
        public static async Task <Document> RemoveNodesAsync(
            this Document document,
            IEnumerable <SyntaxNode> nodes,
            SyntaxRemoveOptions options,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            if (nodes == null)
            {
                throw new ArgumentNullException(nameof(nodes));
            }

            SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode newRoot = root.RemoveNodes(nodes, options);

            return(document.WithSyntaxRoot(newRoot));
        }
        /// <summary>
        /// Creates a new <see cref="UsingDirectiveListInfo"/> with the specified node removed.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public UsingDirectiveListInfo RemoveNode(SyntaxNode node, SyntaxRemoveOptions options)
        {
            ThrowInvalidOperationIfNotInitialized();

            switch (Parent.Kind())
            {
            case SyntaxKind.CompilationUnit:
            {
                var declaration = (CompilationUnitSyntax)Parent;
                declaration = declaration.RemoveNode(node, options);
                return(new UsingDirectiveListInfo(declaration, declaration.Usings));
            }

            case SyntaxKind.NamespaceDeclaration:
            {
                var declaration = (NamespaceDeclarationSyntax)Parent;
                declaration = declaration.RemoveNode(node, options);
                return(new UsingDirectiveListInfo(declaration, declaration.Usings));
            }
            }

            throw new InvalidOperationException();
        }
        private static async Task <StatementListInfo> RefactorAsync <TStatement>(
            Document document,
            TStatement statement,
            StatementListInfo statementsInfo,
            Func <TStatement, TStatement> createNewStatement,
            int count,
            bool removeReturnStatement,
            CancellationToken cancellationToken) where TStatement : StatementSyntax
        {
            int statementIndex = statementsInfo.IndexOf(statement);

            var returnStatement = (ReturnStatementSyntax)statementsInfo[statementIndex + 1];

            ExpressionSyntax returnExpression    = returnStatement.Expression;
            ExpressionSyntax newReturnExpression = null;
            SyntaxTriviaList newTrailingTrivia   = default;

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            ISymbol symbol = semanticModel.GetSymbol(returnExpression, cancellationToken);

            if (symbol.Kind == SymbolKind.Local &&
                statementIndex > 0 &&
                statementsInfo[statementIndex - 1] is LocalDeclarationStatementSyntax localDeclarationStatement &&
                !localDeclarationStatement.ContainsDiagnostics &&
                !localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives() &&
                !statement.GetLeadingTrivia().Any(f => f.IsDirective))
            {
                SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = localDeclarationStatement.Declaration.Variables;

                VariableDeclaratorSyntax declarator = declarators.FirstOrDefault(f => semanticModel.GetDeclaredSymbol(f, cancellationToken)?.Equals(symbol) == true);

                if (declarator != null)
                {
                    ExpressionSyntax value = declarator.Initializer?.Value;

                    if (removeReturnStatement || value != null)
                    {
                        IEnumerable <ReferencedSymbol> referencedSymbols = await SymbolFinder.FindReferencesAsync(symbol, document.Solution(), cancellationToken).ConfigureAwait(false);

                        if (referencedSymbols.First().Locations.Count() == count + 1)
                        {
                            newReturnExpression = value;

                            if (declarators.Count == 1)
                            {
                                if (!removeReturnStatement &&
                                    returnStatement.GetTrailingTrivia().IsEmptyOrWhitespace())
                                {
                                    SyntaxTriviaList trailingTrivia = localDeclarationStatement.GetTrailingTrivia();

                                    if (trailingTrivia
                                        .SkipWhile(f => f.IsWhitespaceTrivia())
                                        .FirstOrDefault()
                                        .IsKind(SyntaxKind.SingleLineCommentTrivia))
                                    {
                                        newTrailingTrivia = trailingTrivia;
                                    }
                                }

                                SyntaxRemoveOptions removeOptions = SyntaxRefactorings.GetRemoveOptions(localDeclarationStatement);

                                if (newTrailingTrivia.Any())
                                {
                                    removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                }

                                statementsInfo = statementsInfo.RemoveNode(localDeclarationStatement, removeOptions);
                                statementIndex--;
                            }
                            else
                            {
                                statementsInfo = statementsInfo.ReplaceNode(localDeclarationStatement, localDeclarationStatement.RemoveNode(declarator, SyntaxRefactorings.GetRemoveOptions(declarator)));
                            }

                            returnStatement = (ReturnStatementSyntax)statementsInfo[statementIndex + 1];
                        }
                    }
                }
            }

            if (removeReturnStatement)
            {
                statementsInfo = statementsInfo.RemoveNode(returnStatement, SyntaxRefactorings.GetRemoveOptions(returnStatement));
            }
            else if (newReturnExpression != null)
            {
                ReturnStatementSyntax newReturnStatement = returnStatement.WithExpression(newReturnExpression.WithTriviaFrom(returnExpression));

                if (newTrailingTrivia.Any())
                {
                    newReturnStatement = newReturnStatement.WithTrailingTrivia(newTrailingTrivia);
                }

                statementsInfo = statementsInfo.ReplaceNode(returnStatement, newReturnStatement);
            }

            StatementSyntax oldNode = statementsInfo[statementIndex];

            TStatement newNode = createNewStatement((TStatement)oldNode).WithFormatterAnnotation();

            return(statementsInfo.ReplaceNode(oldNode, newNode));
        }
Exemple #27
0
 /// <summary>
 /// Removes child nodes.
 /// </summary>
 /// <param name="nodes"></param>
 /// <param name="options"></param>
 /// <returns></returns>
 protected internal override SyntaxNode?RemoveNodesCore(IEnumerable <SyntaxNode> nodes, SyntaxRemoveOptions options)
 => SyntaxNodeRemover.RemoveNodes(this, nodes.Cast <LuaSyntaxNode>(), options).AsRootOfNewTreeWithOptionsFrom(SyntaxTree);
        private async Task <Solution> ProcessResult(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            var locations          = diagnostic.AdditionalLocations;
            var propertyLocation   = locations[0];
            var declaratorLocation = locations[1];

            var declarator         = declaratorLocation.FindToken(cancellationToken).Parent.FirstAncestorOrSelf <TVariableDeclarator>();
            var fieldDocument      = context.Document.Project.GetDocument(declarator.SyntaxTree);
            var fieldSemanticModel = await fieldDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var fieldSymbol = (IFieldSymbol)fieldSemanticModel.GetDeclaredSymbol(declarator);

            var property              = propertyLocation.FindToken(cancellationToken).Parent.FirstAncestorOrSelf <TPropertyDeclaration>();
            var propertyDocument      = context.Document.Project.GetDocument(property.SyntaxTree);
            var propertySemanticModel = await propertyDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var propertySymbol = (IPropertySymbol)propertySemanticModel.GetDeclaredSymbol(property);

            Debug.Assert(fieldDocument.Project == propertyDocument.Project);
            var project     = fieldDocument.Project;
            var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            var solution       = context.Document.Project.Solution;
            var fieldLocations = await Renamer.GetRenameLocationsAsync(
                solution, SymbolAndProjectId.Create(fieldSymbol, fieldDocument.Project.Id),
                solution.Options, cancellationToken).ConfigureAwait(false);

            // First, create the updated property we want to replace the old property with
            var isWrittenToOutsideOfConstructor = IsWrittenToOutsideOfConstructorOrProperty(fieldSymbol, fieldLocations, property, cancellationToken);
            var updatedProperty = await UpdatePropertyAsync(propertyDocument, compilation, fieldSymbol, propertySymbol, property,
                                                            isWrittenToOutsideOfConstructor, cancellationToken).ConfigureAwait(false);

            // Now, rename all usages of the field to point at the property.  Except don't actually
            // rename the field itself.  We want to be able to find it again post rename.
            var updatedSolution = await Renamer.RenameAsync(fieldLocations, propertySymbol.Name,
                                                            location => !location.SourceSpan.IntersectsWith(declaratorLocation.SourceSpan),
                                                            symbols => HasConflict(symbols, propertySymbol, compilation, cancellationToken),
                                                            cancellationToken).ConfigureAwait(false);

            solution = updatedSolution;

            // Now find the field and property again post rename.
            fieldDocument    = solution.GetDocument(fieldDocument.Id);
            propertyDocument = solution.GetDocument(propertyDocument.Id);
            Debug.Assert(fieldDocument.Project == propertyDocument.Project);

            compilation = await fieldDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            fieldSymbol    = (IFieldSymbol)fieldSymbol.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol;
            propertySymbol = (IPropertySymbol)propertySymbol.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol;
            Debug.Assert(fieldSymbol != null && propertySymbol != null);

            declarator = (TVariableDeclarator)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
            var temp = await propertySymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

            property = temp.FirstAncestorOrSelf <TPropertyDeclaration>();

            var nodeToRemove = GetNodeToRemove(declarator);

            const SyntaxRemoveOptions options = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker;

            if (fieldDocument == propertyDocument)
            {
                // Same file.  Have to do this in a slightly complicated fashion.
                var declaratorTreeRoot = await fieldDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var editor = new SyntaxEditor(declaratorTreeRoot, fieldDocument.Project.Solution.Workspace);
                editor.RemoveNode(nodeToRemove, options);
                editor.ReplaceNode(property, updatedProperty);

                var newRoot = editor.GetChangedRoot();
                newRoot = await FormatAsync(newRoot, fieldDocument, cancellationToken).ConfigureAwait(false);

                return(solution.WithDocumentSyntaxRoot(
                           fieldDocument.Id, newRoot));
            }
            else
            {
                // In different files.  Just update both files.
                var fieldTreeRoot = await fieldDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var propertyTreeRoot = await propertyDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var newFieldTreeRoot    = fieldTreeRoot.RemoveNode(nodeToRemove, options);
                var newPropertyTreeRoot = propertyTreeRoot.ReplaceNode(property, updatedProperty);

                newFieldTreeRoot = await FormatAsync(newFieldTreeRoot, fieldDocument, cancellationToken).ConfigureAwait(false);

                newPropertyTreeRoot = await FormatAsync(newPropertyTreeRoot, propertyDocument, cancellationToken).ConfigureAwait(false);

                updatedSolution = solution.WithDocumentSyntaxRoot(fieldDocument.Id, newFieldTreeRoot);
                updatedSolution = updatedSolution.WithDocumentSyntaxRoot(propertyDocument.Id, newPropertyTreeRoot);

                return(updatedSolution);
            }
        }
        private async Task <Solution> ProcessResultAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            var locations          = diagnostic.AdditionalLocations;
            var propertyLocation   = locations[0];
            var declaratorLocation = locations[1];

            var declarator         = declaratorLocation.FindToken(cancellationToken).Parent.FirstAncestorOrSelf <TVariableDeclarator>();
            var fieldDocument      = context.Document.Project.GetDocument(declarator.SyntaxTree);
            var fieldSemanticModel = await fieldDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var fieldSymbol = (IFieldSymbol)fieldSemanticModel.GetDeclaredSymbol(declarator);

            var property              = propertyLocation.FindToken(cancellationToken).Parent.FirstAncestorOrSelf <TPropertyDeclaration>();
            var propertyDocument      = context.Document.Project.GetDocument(property.SyntaxTree);
            var propertySemanticModel = await propertyDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var propertySymbol = (IPropertySymbol)propertySemanticModel.GetDeclaredSymbol(property);

            Debug.Assert(fieldDocument.Project == propertyDocument.Project);
            var project     = fieldDocument.Project;
            var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            var solution       = context.Document.Project.Solution;
            var fieldLocations = await Renamer.GetRenameLocationsAsync(
                solution, SymbolAndProjectId.Create(fieldSymbol, fieldDocument.Project.Id),
                solution.Options, cancellationToken).ConfigureAwait(false);

            // First, create the updated property we want to replace the old property with
            var isWrittenToOutsideOfConstructor = IsWrittenToOutsideOfConstructorOrProperty(fieldSymbol, fieldLocations, property, cancellationToken);
            var updatedProperty = await UpdatePropertyAsync(propertyDocument, compilation, fieldSymbol, propertySymbol, property,
                                                            isWrittenToOutsideOfConstructor, cancellationToken).ConfigureAwait(false);

            // Note: rename will try to update all the references in linked files as well.  However,
            // this can lead to some very bad behavior as we will change the references in linked files
            // but only remove the field and update the property in a single document.  So, you can
            // end in the state where you do this in one of the linked file:
            //
            //      int Prop { get { return this.field; } } => int Prop { get { return this.Prop } }
            //
            // But in the main file we'll replace:
            //
            //      int Prop { get { return this.field; } } => int Prop { get; }
            //
            // The workspace will see these as two irreconcilable edits.  To avoid this, we disallow
            // any edits to the other links for the files containing the field and property.  i.e.
            // rename will only be allowed to edit the exact same doc we're removing the field from
            // and the exact doc we're updating hte property in.  It can't touch the other linked
            // files for those docs.  (It can of course touch any other documents unrelated to the
            // docs that the field and prop are declared in).
            var linkedFiles = new HashSet <DocumentId>();

            linkedFiles.AddRange(fieldDocument.GetLinkedDocumentIds());
            linkedFiles.AddRange(propertyDocument.GetLinkedDocumentIds());

            var canEdit = new Dictionary <SyntaxTree, bool>();

            // Now, rename all usages of the field to point at the property.  Except don't actually
            // rename the field itself.  We want to be able to find it again post rename.
            var updatedSolution = await Renamer.RenameAsync(fieldLocations, propertySymbol.Name,
                                                            location => !location.SourceSpan.IntersectsWith(declaratorLocation.SourceSpan) &&
                                                            CanEditDocument(solution, location.SourceTree, linkedFiles, canEdit),
                                                            symbols => HasConflict(symbols, propertySymbol, compilation, cancellationToken),
                                                            cancellationToken).ConfigureAwait(false);

            solution = updatedSolution;

            // Now find the field and property again post rename.
            fieldDocument    = solution.GetDocument(fieldDocument.Id);
            propertyDocument = solution.GetDocument(propertyDocument.Id);
            Debug.Assert(fieldDocument.Project == propertyDocument.Project);

            compilation = await fieldDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            fieldSymbol    = (IFieldSymbol)fieldSymbol.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol;
            propertySymbol = (IPropertySymbol)propertySymbol.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol;
            Debug.Assert(fieldSymbol != null && propertySymbol != null);

            declarator = (TVariableDeclarator)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
            var temp = await propertySymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

            property = temp.FirstAncestorOrSelf <TPropertyDeclaration>();

            var nodeToRemove = GetNodeToRemove(declarator);

            const SyntaxRemoveOptions options = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker;

            if (fieldDocument == propertyDocument)
            {
                // Same file.  Have to do this in a slightly complicated fashion.
                var declaratorTreeRoot = await fieldDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var editor = new SyntaxEditor(declaratorTreeRoot, fieldDocument.Project.Solution.Workspace);
                editor.RemoveNode(nodeToRemove, options);
                editor.ReplaceNode(property, updatedProperty);

                var newRoot = editor.GetChangedRoot();
                newRoot = await FormatAsync(newRoot, fieldDocument, cancellationToken).ConfigureAwait(false);

                return(solution.WithDocumentSyntaxRoot(
                           fieldDocument.Id, newRoot));
            }
            else
            {
                // In different files.  Just update both files.
                var fieldTreeRoot = await fieldDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var propertyTreeRoot = await propertyDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var newFieldTreeRoot    = fieldTreeRoot.RemoveNode(nodeToRemove, options);
                var newPropertyTreeRoot = propertyTreeRoot.ReplaceNode(property, updatedProperty);

                newFieldTreeRoot = await FormatAsync(newFieldTreeRoot, fieldDocument, cancellationToken).ConfigureAwait(false);

                newPropertyTreeRoot = await FormatAsync(newPropertyTreeRoot, propertyDocument, cancellationToken).ConfigureAwait(false);

                updatedSolution = solution.WithDocumentSyntaxRoot(fieldDocument.Id, newFieldTreeRoot);
                updatedSolution = updatedSolution.WithDocumentSyntaxRoot(propertyDocument.Id, newPropertyTreeRoot);

                return(updatedSolution);
            }
        }
Exemple #30
0
 public RemoveChange(SyntaxNode node, SyntaxRemoveOptions options)
     : base(node)
 {
     _options = options;
 }
Exemple #31
0
 /// <summary>
 /// Remove the node from the tree.
 /// </summary>
 /// <param name="node">The node to remove that currently exists as part of the tree.</param>
 /// <param name="options">Options that affect how node removal works.</param>
 public void RemoveNode(SyntaxNode node, SyntaxRemoveOptions options)
 {
     CheckNodeInTree(node);
     _changes.Add(new RemoveChange(node, options));
 }
Exemple #32
0
 protected internal override SyntaxNode RemoveNodesCore(IEnumerable <SyntaxNode> nodes, SyntaxRemoveOptions options)
 {
     return(SyntaxNodeRemover.RemoveNodes(this, nodes.Cast <CSharpSyntaxNode>(), options));
 }