private async Task <Solution> UpdateReferencesAsync(
            bool updateReferences, Solution solution, Document document, IFieldSymbol field, string finalFieldName, string generatedPropertyName, CancellationToken cancellationToken)
        {
            if (!updateReferences)
            {
                return(solution);
            }

            var projectId = document.Project.Id;

            if (field.IsReadOnly)
            {
                // Inside the constructor we want to rename references the field to the final field name.
                var constructorSyntaxes = GetConstructorNodes(field.ContainingType).ToSet();
                if (finalFieldName != field.Name && constructorSyntaxes.Count > 0)
                {
                    solution = await Renamer.RenameSymbolAsync(solution,
                                                               SymbolAndProjectId.Create(field, projectId),
                                                               finalFieldName, solution.Options,
                                                               location => constructorSyntaxes.Any(c => c.Span.IntersectsWith(location.SourceSpan)),
                                                               cancellationToken : cancellationToken).ConfigureAwait(false);

                    document = solution.GetDocument(document.Id);

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

                    field = field.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol;
                }

                // Outside the constructor we want to rename references to the field to final property name.
                return(await Renamer.RenameSymbolAsync(solution,
                                                       SymbolAndProjectId.Create(field, projectId),
                                                       generatedPropertyName, solution.Options,
                                                       location => !constructorSyntaxes.Any(c => c.Span.IntersectsWith(location.SourceSpan)),
                                                       cancellationToken : cancellationToken).ConfigureAwait(false));
            }
            else
            {
                // Just rename everything.
                return(await Renamer.RenameSymbolAsync(
                           solution, SymbolAndProjectId.Create(field, projectId),
                           generatedPropertyName, solution.Options, cancellationToken).ConfigureAwait(false));
            }
        }
Beispiel #2
0
        public async Task ImmediatelyDerivedTypes_CrossLanguage()
        {
            var solution = new AdhocWorkspace().CurrentSolution;

            // create portable assembly with an abstract base class
            solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.CSharp, @"
namespace N
{
    public abstract class BaseClass { }
}
", MscorlibRefPortable);

            var portableProject = GetPortableProject(solution);

            // create a normal assembly with a type derived from the portable abstract base
            solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.VisualBasic, @"
Imports N
Namespace M
    Public Class DerivedClass
        Inherits BaseClass
    End Class
End Namespace
", MscorlibRef, portableProject.Id);

            // get symbols for types
            var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();

            var baseClassSymbol = portableCompilation.GetTypeByMetadataName("N.BaseClass");

            var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();

            var derivedClassSymbol = normalCompilation.GetTypeByMetadataName("M.DerivedClass");

            // verify that the symbols are different (due to retargeting)
            Assert.NotEqual(baseClassSymbol, derivedClassSymbol.BaseType);

            // verify that the dependent types of `N.BaseClass` correctly resolve to `M.DerivedCLass`
            var derivedFromBase = await DependentTypeFinder.FindImmediatelyDerivedClassesAsync(
                SymbolAndProjectId.Create(baseClassSymbol, portableProject.Id), solution, CancellationToken.None);

            var derivedDependentType = derivedFromBase.Single();

            Assert.Equal(derivedClassSymbol, derivedDependentType.Symbol);
        }
Beispiel #3
0
        public async Task FindReferencesAsync(
            Document document, int position, FindReferencesContext context)
        {
            var cancellationToken = context.CancellationToken;

            cancellationToken.ThrowIfCancellationRequested();

            // Find the symbol we want to search and the solution we want to search in.
            var symbolAndProject = await GetRelevantSymbolAndProjectAtPositionAsync(
                document, position, cancellationToken).ConfigureAwait(false);

            if (symbolAndProject == null)
            {
                return;
            }

            var symbol  = symbolAndProject.Item1;
            var project = symbolAndProject.Item2;

            var displayName = GetDisplayName(symbol);

            context.SetSearchLabel(displayName);

            var progressAdapter = new ProgressAdapter(project.Solution, context);

            // Now call into the underlying FAR engine to find reference.  The FAR
            // engine will push results into the 'progress' instance passed into it.
            // We'll take those results, massage them, and forward them along to the
            // FindReferencesContext instance we were given.
            //
            // Note: we pass along ConfigureAwait(true) because we need to come back
            // to the UI thread.  There's more work we need to do once the FAR engine
            // is done.
            await SymbolFinder.FindReferencesAsync(
                SymbolAndProjectId.Create(symbol, project.Id),
                project.Solution,
                progressAdapter,
                documents : null,
                cancellationToken : cancellationToken).ConfigureAwait(true);

            // After the FAR engine is done call into any third party extensions to see
            // if they want to add results.
            await progressAdapter.CallThirdPartyExtensionsAsync().ConfigureAwait(true);
        }
        private static async Task <ImmutableArray <IMethodSymbol> > FindMethodDeclarationReferences(
            Document invocationDocument, IMethodSymbol method, CancellationToken cancellationToken)
        {
            var progress = new StreamingProgressCollector(StreamingFindReferencesProgress.Instance);

            await SymbolFinder.FindReferencesAsync(
                symbolAndProjectId : SymbolAndProjectId.Create(method, invocationDocument.Project.Id),
                solution : invocationDocument.Project.Solution,
                documents : null,
                progress : progress,
                cancellationToken : cancellationToken).ConfigureAwait(false);

            var referencedSymbols = progress.GetReferencedSymbols();

            return(referencedSymbols.Select(referencedSymbol => referencedSymbol.Definition)
                   .OfType <IMethodSymbol>()
                   .Distinct()
                   .ToImmutableArray());
        }
        /// <summary>
        /// Public helper that we use from features like ObjectBrowser which start with a symbol
        /// and want to push all the references to it into the Streaming-Find-References window.
        /// </summary>
        public static async Task FindSymbolReferencesAsync(
            IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken)
        {
            await context.SetSearchTitleAsync(string.Format(EditorFeaturesResources._0_references,
                                                            FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false);

            var progressAdapter = new FindReferencesProgressAdapter(project.Solution, context);

            // Now call into the underlying FAR engine to find reference.  The FAR
            // engine will push results into the 'progress' instance passed into it.
            // We'll take those results, massage them, and forward them along to the
            // FindReferencesContext instance we were given.
            await SymbolFinder.FindReferencesAsync(
                SymbolAndProjectId.Create(symbol, project.Id),
                project.Solution,
                progressAdapter,
                documents : null,
                cancellationToken : cancellationToken).ConfigureAwait(false);
        }
Beispiel #6
0
        public async Task ImmediatelyDerivedInterfaces_VisualBasic()
        {
            var solution = new AdhocWorkspace().CurrentSolution;

            // create portable assembly with an interface
            solution = AddProjectWithMetadataReferences(solution, "PortableProject", LanguageNames.VisualBasic, @"
Namespace N
    Public Interface IBaseInterface
    End Interface
End Namespace
", MscorlibRefPortable);

            var portableProject = GetPortableProject(solution);

            // create a normal assembly with a type implementing that interface
            solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.VisualBasic, @"
Imports N
Namespace M
    Public Class ImplementingClass
        Implements IBaseInterface
    End Class
End Namespace
", MscorlibRef, portableProject.Id);

            // get symbols for types
            var portableCompilation = await GetPortableProject(solution).GetCompilationAsync();

            var baseInterfaceSymbol = portableCompilation.GetTypeByMetadataName("N.IBaseInterface");

            var normalCompilation = await solution.Projects.Single(p => p.Name == "NormalProject").GetCompilationAsync();

            var implementingClassSymbol = normalCompilation.GetTypeByMetadataName("M.ImplementingClass");

            // verify that the symbols are different (due to retargeting)
            Assert.NotEqual(baseInterfaceSymbol, implementingClassSymbol.Interfaces.Single());

            // verify that the implementing types of `N.IBaseInterface` correctly resolve to `M.ImplementingClass`
            var typesThatImplementInterface = await DependentTypeFinder.FindImmediatelyDerivedAndImplementingTypesAsync(
                SymbolAndProjectId.Create(baseInterfaceSymbol, portableProject.Id), solution, CancellationToken.None);

            Assert.Equal(implementingClassSymbol, typesThatImplementInterface.Single().Symbol);
        }
            private static async Task <ImmutableArray <ReferenceLocation> > FindReferenceLocationsForSymbol(
                Document document, ISymbol symbol, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var progress = new StreamingProgressCollector(StreamingFindReferencesProgress.Instance);

                await SymbolFinder.FindReferencesAsync(
                    symbolAndProjectId : SymbolAndProjectId.Create(symbol, document.Project.Id),
                    solution : document.Project.Solution,
                    documents : null,
                    progress : progress,
                    options : FindReferencesSearchOptions.Default,
                    cancellationToken : cancellationToken).ConfigureAwait(false);

                var referencedSymbols = progress.GetReferencedSymbols();

                return(referencedSymbols.Where(refSymbol => refSymbol.Definition.Equals(symbol))
                       .SelectMany(refSymbol => refSymbol.Locations).ToImmutableArray());
            }
Beispiel #8
0
        private static bool TypeDerivesFrom(
            SymbolAndProjectIdSet metadataTypes, INamedTypeSymbol type, bool transitive)
        {
            if (transitive)
            {
                for (var current = type.BaseType; current != null; current = current.BaseType)
                {
                    if (metadataTypes.Contains(
                            SymbolAndProjectId.Create(current.OriginalDefinition, projectId: null)))
                    {
                        return(true);
                    }
                }

                return(false);
            }
            else
            {
                return(metadataTypes.Contains(
                           SymbolAndProjectId.Create(type.BaseType?.OriginalDefinition, projectId: null)));
            }
        }
Beispiel #9
0
        private static async Task FindImmediateMatchingMetadataTypesInMetadataReferenceAsync(
            SymbolAndProjectIdSet metadataTypes,
            Project project,
            Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches,
            Compilation compilation,
            PortableExecutableReference reference,
            SymbolAndProjectIdSet result,
            CancellationToken cancellationToken)
        {
            // We store an index in SymbolTreeInfo of the *simple* metadata type name
            // to the names of the all the types that either immediately derive or
            // implement that type.  Because the mapping is from the simple name
            // we might get false positives.  But that's fine as we still use
            // 'metadataTypeMatches' to make sure the match is correct.
            var symbolTreeInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync(
                project.Solution, reference, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false);

            // For each type we care about, see if we can find any derived types
            // in this index.
            foreach (var metadataType in metadataTypes)
            {
                var baseTypeName = metadataType.Symbol.Name;

                // For each derived type we find, see if we can map that back
                // to an actual symbol.  Then check if that symbol actually fits
                // our criteria.
                foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken))
                {
                    if (derivedType != null && derivedType.Locations.Any(s_isInMetadata))
                    {
                        if (metadataTypeMatches(metadataTypes, derivedType))
                        {
                            result.Add(SymbolAndProjectId.Create(derivedType, project.Id));
                        }
                    }
                }
            }
        }
        private async Task <ProgressAdapter> FindReferencesWorkerAsync(
            Document document, int position, IFindUsagesContext context)
        {
            var cancellationToken = context.CancellationToken;

            cancellationToken.ThrowIfCancellationRequested();

            // Find the symbol we want to search and the solution we want to search in.
            var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                document, position, cancellationToken).ConfigureAwait(false);

            if (symbolAndProject == null)
            {
                return(null);
            }

            var symbol  = symbolAndProject?.symbol;
            var project = symbolAndProject?.project;

            var displayName = AbstractFindReferencesService.GetDisplayName(symbol);

            context.SetSearchLabel(displayName);

            var progressAdapter = new ProgressAdapter(project.Solution, context);

            // Now call into the underlying FAR engine to find reference.  The FAR
            // engine will push results into the 'progress' instance passed into it.
            // We'll take those results, massage them, and forward them along to the
            // FindReferencesContext instance we were given.
            await SymbolFinder.FindReferencesAsync(
                SymbolAndProjectId.Create(symbol, project.Id),
                project.Solution,
                progressAdapter,
                documents : null,
                cancellationToken : cancellationToken).ConfigureAwait(false);

            return(progressAdapter);
        }
Beispiel #11
0
        public void Run(object data)
        {
            var doc = IdeApp.Workbench.ActiveDocument;

            if (doc == null || doc.FileName == FilePath.Null)
            {
                return;
            }

            var info = RefactoringSymbolInfo.GetSymbolInfoAsync(doc, doc.Editor).Result;
            var sym  = info.Symbol ?? info.DeclaredSymbol;

            if (sym != null)
            {
                if (sym.Kind == SymbolKind.Local || sym.Kind == SymbolKind.Parameter || sym.Kind == SymbolKind.TypeParameter)
                {
                    FindReferencesHandler.FindRefs(new [] { SymbolAndProjectId.Create(sym, doc.AnalysisDocument.Project.Id) }, doc.AnalysisDocument.Project.Solution).Ignore();
                }
                else
                {
                    RefactoringService.FindAllReferencesAsync(FindReferencesHandler.FilterSymbolForFindReferences(sym).GetDocumentationCommentId()).Ignore();
                }
            }
        }
        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);
            }
        }
Beispiel #13
0
        protected override async Task UpdateAsync(CommandArrayInfo ainfo, CancellationToken cancelToken)
        {
            if (!TryGetDocument(out var analysisDocument, out var doc))
            {
                return;
            }
            var semanticModel = await analysisDocument.GetSemanticModelAsync(cancelToken);

            if (semanticModel == null)
            {
                return;
            }
            var info = await RefactoringSymbolInfo.GetSymbolInfoAsync(doc.DocumentContext, doc.Editor, cancelToken);

            var ext = doc.GetContent <CodeActionEditorExtension> ();

            bool canRename = RenameHandler.CanRename(info.Symbol ?? info.DeclaredSymbol);

            if (canRename)
            {
                ainfo.Add(IdeApp.CommandService.GetCommandInfo(MonoDevelop.Ide.Commands.EditCommands.Rename), new Action(async delegate {
                    await new MonoDevelop.Refactoring.Rename.RenameRefactoring().Rename(info.Symbol ?? info.DeclaredSymbol);
                }));
            }

            bool isSortAndRemoveUsingsSupported = RemoveAndSortUsingsHandler.IsSortAndRemoveImportsSupported(analysisDocument, doc.GetContent <Microsoft.VisualStudio.Text.ITextBuffer>());

            if (isSortAndRemoveUsingsSupported)
            {
                var sortAndRemoveImportsInfo = IdeApp.CommandService.GetCommandInfo(Commands.SortAndRemoveImports);
                sortAndRemoveImportsInfo.Enabled = true;
                ainfo.Add(sortAndRemoveImportsInfo, new Action(async delegate {
                    await RemoveAndSortUsingsHandler.SortAndRemoveUnusedImports(analysisDocument, cancelToken);
                }));
            }

            var gotoDeclarationSymbol = info.Symbol;

            if (gotoDeclarationSymbol == null && info.DeclaredSymbol != null && info.DeclaredSymbol.Locations.Length > 1)
            {
                gotoDeclarationSymbol = info.DeclaredSymbol;
            }
            if (IdeApp.ProjectOperations.CanJumpToDeclaration(gotoDeclarationSymbol) || gotoDeclarationSymbol == null && IdeApp.ProjectOperations.CanJumpToDeclaration(info.CandidateSymbols.FirstOrDefault()))
            {
                var type = (gotoDeclarationSymbol ?? info.CandidateSymbols.FirstOrDefault()) as INamedTypeSymbol;
                if (type != null && type.Locations.Length > 1)
                {
                    var declSet = new CommandInfoSet();
                    declSet.Text = GettextCatalog.GetString("_Go to Declaration");
                    foreach (var part in type.Locations)
                    {
                        var loc = part.GetLineSpan();
                        declSet.CommandInfos.Add(string.Format(GettextCatalog.GetString("{0}, Line {1}"), FormatFileName(part.SourceTree.FilePath), loc.StartLinePosition.Line + 1), new Action(() => IdeApp.ProjectOperations.JumpTo(type, part, doc.Owner)));
                    }
                    ainfo.Add(declSet);
                }
                else
                {
                    ainfo.Add(IdeApp.CommandService.GetCommandInfo(RefactoryCommands.GotoDeclaration), new Action(() => GotoDeclarationHandler.Run(doc)));
                }
            }


            if (info.DeclaredSymbol != null && GotoBaseDeclarationHandler.CanGotoBase(info.DeclaredSymbol))
            {
                ainfo.Add(GotoBaseDeclarationHandler.GetDescription(info.DeclaredSymbol), new Action(() => GotoBaseDeclarationHandler.GotoBase(doc, info.DeclaredSymbol).Ignore()));
            }

            var sym = info.Symbol ?? info.DeclaredSymbol;

            if (doc.DocumentContext.HasProject && sym != null)
            {
                ainfo.Add(IdeApp.CommandService.GetCommandInfo(RefactoryCommands.FindReferences), new System.Action(() => {
                    if (sym.Kind == SymbolKind.Local || sym.Kind == SymbolKind.Parameter || sym.Kind == SymbolKind.TypeParameter)
                    {
                        FindReferencesHandler.FindRefs(new [] { SymbolAndProjectId.Create(sym, analysisDocument.Project.Id) }, analysisDocument.Project.Solution).Ignore();
                    }
                    else
                    {
                        RefactoringService.FindReferencesAsync(FindReferencesHandler.FilterSymbolForFindReferences(sym).GetDocumentationCommentId()).Ignore();
                    }
                }));
                try {
                    if (Microsoft.CodeAnalysis.FindSymbols.SymbolFinder.FindSimilarSymbols(sym, semanticModel.Compilation).Count() > 1)
                    {
                        ainfo.Add(IdeApp.CommandService.GetCommandInfo(RefactoryCommands.FindAllReferences), new System.Action(() => RefactoringService.FindAllReferencesAsync(FindReferencesHandler.FilterSymbolForFindReferences(sym).GetDocumentationCommentId())));
                    }
                } catch (Exception) {
                    // silently ignore roslyn bug.
                }
            }
        }
        public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context)
        {
            var cancellationToken = context.CancellationToken;
            var symbolAndProject  = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
                document, position, cancellationToken).ConfigureAwait(false);

            if (symbolAndProject == default)
            {
                await context.ReportMessageAsync(
                    EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret).ConfigureAwait(false);

                return;
            }

            var symbol = symbolAndProject.Value.symbol;
            var bases  = FindBaseHelpers.FindBases(
                symbol, symbolAndProject.Value.project, cancellationToken);

            await context.SetSearchTitleAsync(
                string.Format(EditorFeaturesResources._0_bases,
                              FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false);

            var project   = document.Project;
            var solution  = project.Solution;
            var projectId = project.Id;

            var found = false;

            // For each potential base, try to find its definition in sources.
            // If found, add its' definitionItem to the context.
            // If not found but the symbol is from metadata, create its' definition item from metadata and add to the context.
            foreach (var baseSymbol in bases)
            {
                var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(
                    SymbolAndProjectId.Create(baseSymbol, projectId), solution, cancellationToken).ConfigureAwait(false);

                if (sourceDefinition.Symbol != null &&
                    sourceDefinition.Symbol.Locations.Any(l => l.IsInSource))
                {
                    var definitionItem = await sourceDefinition.Symbol.ToClassifiedDefinitionItemAsync(
                        solution.GetProject(sourceDefinition.ProjectId), includeHiddenLocations : false,
                        FindReferencesSearchOptions.Default, cancellationToken : cancellationToken)
                                         .ConfigureAwait(false);

                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);

                    found = true;
                }
                else if (baseSymbol.Locations.Any(l => l.IsInMetadata))
                {
                    var definitionItem = baseSymbol.ToNonClassifiedDefinitionItem(
                        project, includeHiddenLocations: true);
                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);

                    found = true;
                }
            }

            if (!found)
            {
                await context.ReportMessageAsync(EditorFeaturesResources.The_symbol_has_no_base)
                .ConfigureAwait(false);
            }
        }
        private bool TryCreateUpdatedSolution(
            ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken, out Solution updatedSolution)
        {
            updatedSolution = context.Solution;
            var declaredSymbol = context.Symbol;

            var nodesToUpdate   = new Dictionary <DocumentId, List <SyntaxNode> >();
            var definitionToUse = new Dictionary <SyntaxNode, ISymbol>();

            bool hasLocationsInMetadata = false;

            var symbols = FindChangeSignatureReferencesAsync(
                SymbolAndProjectId.Create(declaredSymbol, context.Project.Id),
                context.Solution, cancellationToken).WaitAndGetResult(cancellationToken);

            foreach (var symbol in symbols)
            {
                if (symbol.Definition.Kind == SymbolKind.Method &&
                    ((symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertyGet || (symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertySet))
                {
                    continue;
                }

                if (symbol.Definition.Kind == SymbolKind.NamedType)
                {
                    continue;
                }

                if (symbol.Definition.Locations.Any(loc => loc.IsInMetadata))
                {
                    hasLocationsInMetadata = true;
                    continue;
                }

                var symbolWithSyntacticParameters = symbol.Definition;
                var symbolWithSemanticParameters  = symbol.Definition;

                var includeDefinitionLocations = true;

                if (symbol.Definition.Kind == SymbolKind.Field)
                {
                    includeDefinitionLocations = false;
                }

                if (symbolWithSyntacticParameters.Kind == SymbolKind.Event)
                {
                    var eventSymbol = symbolWithSyntacticParameters as IEventSymbol;
                    var type        = eventSymbol.Type as INamedTypeSymbol;
                    if (type != null && type.DelegateInvokeMethod != null)
                    {
                        symbolWithSemanticParameters = type.DelegateInvokeMethod;
                    }
                    else
                    {
                        continue;
                    }
                }

                if (symbolWithSyntacticParameters.Kind == SymbolKind.Method)
                {
                    var methodSymbol = symbolWithSyntacticParameters as IMethodSymbol;
                    if (methodSymbol.MethodKind == MethodKind.DelegateInvoke)
                    {
                        symbolWithSyntacticParameters = methodSymbol.ContainingType;
                    }

                    if (methodSymbol.Name == WellKnownMemberNames.DelegateBeginInvokeName &&
                        methodSymbol.ContainingType != null &&
                        methodSymbol.ContainingType.IsDelegateType())
                    {
                        includeDefinitionLocations = false;
                    }
                }

                // Find and annotate all the relevant definitions

                if (includeDefinitionLocations)
                {
                    foreach (var def in symbolWithSyntacticParameters.Locations)
                    {
                        DocumentId documentId;
                        SyntaxNode nodeToUpdate;
                        if (!TryGetNodeWithEditableSignatureOrAttributes(def, updatedSolution, out nodeToUpdate, out documentId))
                        {
                            continue;
                        }

                        if (!nodesToUpdate.ContainsKey(documentId))
                        {
                            nodesToUpdate.Add(documentId, new List <SyntaxNode>());
                        }

                        AddUpdatableNodeToDictionaries(nodesToUpdate, documentId, nodeToUpdate, definitionToUse, symbolWithSemanticParameters);
                    }
                }

                // Find and annotate all the relevant references

                foreach (var location in symbol.Locations)
                {
                    if (location.Location.IsInMetadata)
                    {
                        hasLocationsInMetadata = true;
                        continue;
                    }

                    DocumentId documentId2;
                    SyntaxNode nodeToUpdate2;
                    if (!TryGetNodeWithEditableSignatureOrAttributes(location.Location, updatedSolution, out nodeToUpdate2, out documentId2))
                    {
                        continue;
                    }

                    if (!nodesToUpdate.ContainsKey(documentId2))
                    {
                        nodesToUpdate.Add(documentId2, new List <SyntaxNode>());
                    }

                    AddUpdatableNodeToDictionaries(nodesToUpdate, documentId2, nodeToUpdate2, definitionToUse, symbolWithSemanticParameters);
                }
            }

            if (hasLocationsInMetadata)
            {
                var notificationService = context.Solution.Workspace.Services.GetService <INotificationService>();
                if (!notificationService.ConfirmMessageBox(FeaturesResources.This_symbol_has_related_definitions_or_references_in_metadata_Changing_its_signature_may_result_in_build_errors_Do_you_want_to_continue, severity: NotificationSeverity.Warning))
                {
                    return(false);
                }
            }

            // Construct all the relevant syntax trees from the base solution

            var updatedRoots = new Dictionary <DocumentId, SyntaxNode>();

            foreach (var docId in nodesToUpdate.Keys)
            {
                var doc     = updatedSolution.GetDocument(docId);
                var updater = doc.Project.LanguageServices.GetService <AbstractChangeSignatureService>();
                var root    = doc.GetSyntaxRootSynchronously(CancellationToken.None);

                var nodes = nodesToUpdate[docId];

                var newRoot = root.ReplaceNodes(nodes, (originalNode, potentiallyUpdatedNode) =>
                {
                    return(updater.ChangeSignature(doc, definitionToUse[originalNode], potentiallyUpdatedNode, originalNode, CreateCompensatingSignatureChange(definitionToUse[originalNode], options.UpdatedSignature), cancellationToken));
                });

                var annotatedNodes = newRoot.GetAnnotatedNodes <SyntaxNode>(syntaxAnnotation: changeSignatureFormattingAnnotation);

                var formattedRoot = Formatter.FormatAsync(
                    newRoot,
                    changeSignatureFormattingAnnotation,
                    doc.Project.Solution.Workspace,
                    options: null,
                    rules: GetFormattingRules(doc),
                    cancellationToken: CancellationToken.None).WaitAndGetResult(CancellationToken.None);

                updatedRoots[docId] = formattedRoot;
            }

            // Update the documents using the updated syntax trees

            foreach (var docId in nodesToUpdate.Keys)
            {
                updatedSolution = updatedSolution.WithDocumentSyntaxRoot(docId, updatedRoots[docId]);
            }

            return(true);
        }
        private bool TryCreateUpdatedSolution(
            ChangeSignatureAnalyzedContext context, ChangeSignatureOptionsResult options, CancellationToken cancellationToken, out Solution updatedSolution)
        {
            updatedSolution = context.Solution;
            var declaredSymbol = context.Symbol;

            var nodesToUpdate   = new Dictionary <DocumentId, List <SyntaxNode> >();
            var definitionToUse = new Dictionary <SyntaxNode, ISymbol>();

            bool hasLocationsInMetadata = false;

            var symbols = FindChangeSignatureReferencesAsync(
                SymbolAndProjectId.Create(declaredSymbol, context.Project.Id),
                context.Solution, cancellationToken).WaitAndGetResult(cancellationToken);

            foreach (var symbol in symbols)
            {
                if (symbol.Definition.Kind == SymbolKind.Method &&
                    ((symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertyGet || (symbol.Definition as IMethodSymbol).MethodKind == MethodKind.PropertySet))
                {
                    continue;
                }

                if (symbol.Definition.Kind == SymbolKind.NamedType)
                {
                    continue;
                }

                if (symbol.Definition.Locations.Any(loc => loc.IsInMetadata))
                {
                    hasLocationsInMetadata = true;
                    continue;
                }

                var symbolWithSyntacticParameters = symbol.Definition;
                var symbolWithSemanticParameters  = symbol.Definition;

                var includeDefinitionLocations = true;

                if (symbol.Definition.Kind == SymbolKind.Field)
                {
                    includeDefinitionLocations = false;
                }

                if (symbolWithSyntacticParameters.Kind == SymbolKind.Event)
                {
                    var eventSymbol = symbolWithSyntacticParameters as IEventSymbol;
                    if (eventSymbol.Type is INamedTypeSymbol type && type.DelegateInvokeMethod != null)
                    {
                        symbolWithSemanticParameters = type.DelegateInvokeMethod;
                    }
                    else
                    {
                        continue;
                    }
                }

                if (symbolWithSyntacticParameters.Kind == SymbolKind.Method)
                {
                    var methodSymbol = symbolWithSyntacticParameters as IMethodSymbol;
                    if (methodSymbol.MethodKind == MethodKind.DelegateInvoke)
                    {
                        symbolWithSyntacticParameters = methodSymbol.ContainingType;
                    }

                    if (methodSymbol.Name == WellKnownMemberNames.DelegateBeginInvokeName &&
                        methodSymbol.ContainingType != null &&
                        methodSymbol.ContainingType.IsDelegateType())
                    {
                        includeDefinitionLocations = false;
                    }
                }

                // Find and annotate all the relevant definitions

                if (includeDefinitionLocations)
                {
                    foreach (var def in symbolWithSyntacticParameters.Locations)
                    {
                        if (!TryGetNodeWithEditableSignatureOrAttributes(def, updatedSolution, out var nodeToUpdate, out var documentId))
                        {
                            continue;
                        }

                        if (!nodesToUpdate.ContainsKey(documentId))
                        {
                            nodesToUpdate.Add(documentId, new List <SyntaxNode>());
                        }

                        AddUpdatableNodeToDictionaries(nodesToUpdate, documentId, nodeToUpdate, definitionToUse, symbolWithSemanticParameters);
                    }
                }

                // Find and annotate all the relevant references

                foreach (var location in symbol.Locations)
                {
                    if (location.Location.IsInMetadata)
                    {
                        hasLocationsInMetadata = true;
                        continue;
                    }

                    if (!TryGetNodeWithEditableSignatureOrAttributes(location.Location, updatedSolution, out var nodeToUpdate2, out var documentId2))
                    {
                        continue;
                    }

                    if (!nodesToUpdate.ContainsKey(documentId2))
                    {
                        nodesToUpdate.Add(documentId2, new List <SyntaxNode>());
                    }

                    AddUpdatableNodeToDictionaries(nodesToUpdate, documentId2, nodeToUpdate2, definitionToUse, symbolWithSemanticParameters);
                }
            }
        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);
            }
        }
        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 the 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);

            // If we have a situation where the property is the second member in a type, and it
            // would become the first, then remove any leading blank lines from it so we don't have
            // random blanks above it that used to space it from the field that was there.
            //
            // The reason we do this special processing is that the first member of a type tends to
            // be special wrt leading trivia. i.e. users do not normally put blank lines before the
            // first member. And so, when a type now becomes the first member, we want to follow the
            // user's common pattern here.
            //
            // In all other code cases, i.e.when there are multiple fields above, or the field is
            // below the property, then the property isn't now becoming "the first member", and as
            // such, it doesn't want this special behavior about it's leading blank lines. i.e. if
            // the user has:
            //
            //  class C
            //  {
            //      int i;
            //      int j;
            //
            //      int Prop => j;
            //  }
            //
            // Then if we remove 'j' (or even 'i'), then 'Prop' would stay the non-first member, and
            // would definitely want to keep that blank line above it.
            //
            // In essence, the blank line above the property exists for separation from what's above
            // it. As long as something is above it, we keep the separation. However, if the
            // property becomes the first member in the type, the separation is now inappropriate
            // because there's nothing to actually separate it from.
            if (fieldDocument == propertyDocument)
            {
                var syntaxFacts = fieldDocument.GetLanguageService <ISyntaxFactsService>();
                if (WillRemoveFirstFieldInTypeDirectlyAboveProperty(syntaxFacts, property, nodeToRemove) &&
                    syntaxFacts.GetLeadingBlankLines(nodeToRemove).Length == 0)
                {
                    updatedProperty = syntaxFacts.GetNodeWithoutLeadingBlankLines(updatedProperty);
                }
            }

            var syntaxRemoveOptions = CreateSyntaxRemoveOptions(nodeToRemove);

            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.ReplaceNode(property, updatedProperty);
                editor.RemoveNode(nodeToRemove, syntaxRemoveOptions);

                var newRoot = editor.GetChangedRoot();
                newRoot = Format(newRoot, fieldDocument, cancellationToken);

                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, syntaxRemoveOptions);
                var newPropertyTreeRoot = propertyTreeRoot.ReplaceNode(property, updatedProperty);

                newFieldTreeRoot    = Format(newFieldTreeRoot, fieldDocument, cancellationToken);
                newPropertyTreeRoot = Format(newPropertyTreeRoot, propertyDocument, cancellationToken);

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

                return(updatedSolution);
            }
        }