private async Task <Document> InlineTemporaryAsync(Document document, VariableDeclarationSyntax declarator, CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; // Annotate the variable declarator so that we can get back to it later. var updatedDocument = await document.ReplaceNodeAsync(declarator, declarator.WithAdditionalAnnotations(DefinitionAnnotation), cancellationToken).ConfigureAwait(false); var semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); // Create the expression that we're actually going to inline. var expressionToInline = await CreateExpressionToInlineAsync(variableDeclarator, updatedDocument, cancellationToken).ConfigureAwait(false); // Collect the identifier names for each reference. var local = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken); var symbolRefs = await SymbolFinder.FindReferencesAsync(local, updatedDocument.Project.Solution, cancellationToken).ConfigureAwait(false); var references = symbolRefs.Single(r => r.Definition == local).Locations; var syntaxRoot = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Collect the topmost parenting expression for each reference. var nonConflictingIdentifierNodes = references .Select(loc => (IdentifierNameSyntax)syntaxRoot.FindToken(loc.Location.SourceSpan.Start).Parent) .Where(ident => !HasConflict(ident, variableDeclarator)); // Add referenceAnnotations to identifier nodes being replaced. updatedDocument = await updatedDocument.ReplaceNodesAsync( nonConflictingIdentifierNodes, (o, n) => n.WithAdditionalAnnotations(ReferenceAnnotation), cancellationToken).ConfigureAwait(false); semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); // Get the annotated reference nodes. nonConflictingIdentifierNodes = await FindReferenceAnnotatedNodesAsync(updatedDocument, cancellationToken).ConfigureAwait(false); var topmostParentingExpressions = nonConflictingIdentifierNodes .Select(ident => GetTopMostParentingExpression(ident)) .Distinct(); var originalInitializerSymbolInfo = semanticModel.GetSymbolInfo(variableDeclarator.Initializer.Value, cancellationToken); // Make each topmost parenting statement or Equals Clause Expressions semantically explicit. updatedDocument = await updatedDocument.ReplaceNodesAsync(topmostParentingExpressions, (o, n) => Simplifier.Expand(n, semanticModel, workspace, cancellationToken: cancellationToken), cancellationToken).ConfigureAwait(false); semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var semanticModelBeforeInline = semanticModel; variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); var scope = GetScope(variableDeclarator); var newScope = ReferenceRewriter.Visit(semanticModel, scope, variableDeclarator, expressionToInline, cancellationToken); updatedDocument = await updatedDocument.ReplaceNodeAsync(scope, newScope, cancellationToken).ConfigureAwait(false); semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false); newScope = GetScope(variableDeclarator); var conflicts = newScope.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind); var declaratorConflicts = variableDeclarator.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind); // Note that we only remove the local declaration if there weren't any conflicts, // unless those conflicts are inside the local declaration. if (conflicts.Count() == declaratorConflicts.Count()) { // Certain semantic conflicts can be detected only after the reference rewriter has inlined the expression var newDocument = await DetectSemanticConflicts(updatedDocument, semanticModel, semanticModelBeforeInline, originalInitializerSymbolInfo, cancellationToken).ConfigureAwait(false); if (updatedDocument == newDocument) { // No semantic conflicts, we can remove the definition. updatedDocument = await updatedDocument.ReplaceNodeAsync(newScope, RemoveDeclaratorFromScope(variableDeclarator, newScope), cancellationToken).ConfigureAwait(false); } else { // There were some semantic conflicts, don't remove the definition. updatedDocument = newDocument; } } return(updatedDocument); }