Ejemplo n.º 1
0
        public SyntaxNode ExpandNode(SyntaxNode node, SyntaxNode root, SemanticModel semanticModel,
                                     Workspace workspace)
        {
            SyntaxNode expandedNode = Simplifier.Expand(node, semanticModel, workspace);

            return(WithoutGlobalOverqualification(node, expandedNode));
        }
Ejemplo n.º 2
0
        private async Task <Document> InlineTemporaryAsync(Document document, VariableDeclaratorSyntax 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 => Equals(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().ToList();

            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) =>
            {
                var node = Simplifier.Expand(n, semanticModel, workspace, cancellationToken: cancellationToken);

                // warn when inlining into a conditional expression, as the inlined expression will not be executed.
                if (semanticModel.GetSymbolInfo(o).Symbol is IMethodSymbol {
                    IsConditional : true
                })
                {
                    node = node.WithAdditionalAnnotations(
                        WarningAnnotation.Create(CSharpFeaturesResources.Warning_Inlining_temporary_into_conditional_method_call));
                }
                return(node);
            }, cancellationToken).ConfigureAwait(false);
Ejemplo n.º 3
0
            public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
            {
                // We only care about xml doc comments
                var leadingTrivia = CanHaveDocComments(node) ? VisitList(node.GetLeadingTrivia()) : node.GetLeadingTrivia();

                if (_namespaceMembers.Contains(node.Identifier.Text))
                {
                    var expanded = Simplifier.Expand <SyntaxNode>(node, _model, _workspace, cancellationToken: _cancellationToken);
                    return(expanded.WithLeadingTrivia(leadingTrivia));
                }

                return(node.WithLeadingTrivia(leadingTrivia));
            }
Ejemplo n.º 4
0
            public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
            {
                // No need to visit trivia, as we only care about xml doc comments
                if (node.Expression is MemberAccessExpressionSyntax memberAccess)
                {
                    if (_extensionMethods.Contains(memberAccess.Name.Identifier.Text))
                    {
                        // No need to visit this as simplifier will expand everything
                        return(Simplifier.Expand <SyntaxNode>(node, _model, _workspace, cancellationToken: _cancellationToken));
                    }
                }

                return(base.VisitInvocationExpression(node) ?? throw ExceptionUtilities.Unreachable);
            }
Ejemplo n.º 5
0
 public SyntaxNode ExpandNode(SyntaxNode node, SyntaxNode root, SemanticModel semanticModel,
     Workspace workspace)
 {
     var symbol = semanticModel.GetSymbolInfo(node).Symbol;
     if (node is SimpleNameSyntax sns && IsMyBaseBug(node, symbol, root, semanticModel) && semanticModel.GetOperation(node) is IMemberReferenceOperation mro && mro.Instance != null) {
         var expressionSyntax = (ExpressionSyntax)mro.Instance.Syntax;
         return MemberAccess(expressionSyntax, sns);
     }
     if (node is MemberAccessExpressionSyntax maes && IsTypePromotion(node, symbol, root, semanticModel) && semanticModel.GetOperation(node) is IMemberReferenceOperation mro2 && mro2.Instance != null) {
         var expressionSyntax = (ExpressionSyntax)mro2.Instance.Syntax;
         return MemberAccess(expressionSyntax, SyntaxFactory.IdentifierName(mro2.Member.Name));
     }
     return IsOriginalSymbolGenericMethod(semanticModel, node) ? node : Simplifier.Expand(node, semanticModel, workspace);
 }
Ejemplo n.º 6
0
            public override SyntaxNode VisitGenericName(GenericNameSyntax node)
            {
                // We only care about xml doc comments
                var leadingTrivia = CanHaveDocComments(node) ? VisitList(node.GetLeadingTrivia()) : node.GetLeadingTrivia();

                if (_namespaceMembers.Contains(node.Identifier.Text))
                {
                    // No need to visit type argument list as simplifier will expand everything
                    var expanded = Simplifier.Expand <SyntaxNode>(node, _model, _workspace, cancellationToken: _cancellationToken);
                    return(expanded.WithLeadingTrivia(leadingTrivia));
                }

                var typeArgumentList = (TypeArgumentListSyntax)base.Visit(node.TypeArgumentList);

                return(node.Update(node.Identifier.WithLeadingTrivia(leadingTrivia), typeArgumentList));
            }
Ejemplo n.º 7
0
        private async Task <Document> InlineTemporaryAsync(Document document, VariableDeclaratorSyntax 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 => Equals(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);
        }
        private static async Task <Document> InlineTemporaryAsync(Document document, VariableDeclaratorSyntax 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 referencedSymbol = symbolRefs.SingleOrDefault(r => Equals(r.Definition, local));
            var references       = referencedSymbol == null?SpecializedCollections.EmptyEnumerable <ReferenceLocation>() : referencedSymbol.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().ToList();

            var originalInitializerSymbolInfo = semanticModel.GetSymbolInfo(variableDeclarator.Initializer.Value, cancellationToken);

            // Checks to see if inlining the temporary variable may change the code's meaning. This can only apply if the variable has two or more
            // references. We later use this heuristic to determine whether or not to display a warning message to the user.
            var mayContainSideEffects = references.Count() > 1 &&
                                        MayContainSideEffects(variableDeclarator.Initializer.Value);

            // Make each topmost parenting statement or Equals Clause Expressions semantically explicit.
            updatedDocument = await updatedDocument.ReplaceNodesAsync(topmostParentingExpressions, (o, n) =>
            {
                var node = Simplifier.Expand(n, semanticModel, workspace, cancellationToken: cancellationToken);

                // warn when inlining into a conditional expression, as the inlined expression will not be executed.
                if (semanticModel.GetSymbolInfo(o).Symbol is IMethodSymbol {
                    IsConditional : true
                })
                {
                    node = node.WithAdditionalAnnotations(
                        WarningAnnotation.Create(CSharpFeaturesResources.Warning_Inlining_temporary_into_conditional_method_call));
                }

                // If the refactoring may potentially change the code's semantics, display a warning message to the user.
                if (mayContainSideEffects)
                {
                    node = node.WithAdditionalAnnotations(
                        WarningAnnotation.Create(CSharpFeaturesResources.Warning_Inlining_temporary_variable_may_change_code_meaning));
                }

                return(node);
            }, cancellationToken).ConfigureAwait(false);
        /// TODO: this might be better as a visitor
        /// offer to break out the continuation into a success event handler the exception block into an error event handler
        /// TODO: hooking them up where other bus.AddHandlers are called
        /// and replace RequestAsync with Send
        /// with TODOs to verify storage of state and retrieval of state
        private static async Task <Solution> InvokeMp0102(Diagnostic diagnostic, Solution solution, Document document,
                                                          CancellationToken cancellationToken)
        {
            // the diagnostic.Location here will be the span of the RequestAsync<> GenericNameSyntax object

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

            var model = await document.GetSemanticModelAsync(cancellationToken);

            var generator = SyntaxGenerator.GetGenerator(document);

            MemberAccessExpressionSyntax requestAsyncMemberAccess;
            SyntaxNode requestAsyncInvocationStatement;

            StatementSyntax[] requestAsyncAndDependantStatements;
            string            fullContainingNamespaceName;
            SyntaxToken       handleMethodParameterName;
            var containingMemberAnnotation = new SyntaxAnnotation(Guid.NewGuid().ToString("D"));
            var tryAnnotation         = new SyntaxAnnotation(Guid.NewGuid().ToString("D"));
            var subjectNodeAnnotation = new SyntaxAnnotation(Guid.NewGuid().ToString("D"));
            INamedTypeSymbol  errorEventType;
            INamedTypeSymbol  eventType;
            BlockSyntax       eventHandlerHandleMethodBody;
            SyntaxToken       catchExceptionIdentifier = default(SyntaxToken);
            CatchClauseSyntax catchStatement           = null;
            SyntaxToken       errorEventHandlerMessageParameterIdentifier;
            {
                var subjectNode = root.FindNode(diagnostic.Location.SourceSpan);
                requestAsyncMemberAccess = subjectNode.Parent.AncestorsAndSelf().OfType <MemberAccessExpressionSyntax>().First();

                INamedTypeSymbol messageType;
                Utilities.GetRequestAsyncInfo(requestAsyncMemberAccess, model, out messageType, out eventType, out errorEventType);

                // Get span of code around RequestAsync for event handler
                handleMethodParameterName = Identifier(
                    requestAsyncMemberAccess.GetAssignmentSymbol(model, cancellationToken).Name);

                document = document.ReplaceNode(subjectNode, subjectNode.WithAdditionalAnnotations(subjectNodeAnnotation), out root,
                                                out model);
                subjectNode = root.GetAnnotatedNodes(subjectNodeAnnotation).Single();

                var containingMember = subjectNode.GetContainingMemberDeclaration() as MethodDeclarationSyntax;
                Debug.Assert(containingMember != null, "containingMember != null");
                fullContainingNamespaceName =
                    // ReSharper disable once PossibleNullReferenceException
                    model.GetDeclaredSymbol(containingMember.Parent, cancellationToken).ContainingNamespace.GetFullNamespaceName();

                document = document.ReplaceNode(containingMember,
                                                containingMember
                                                .WithAdditionalAnnotations(containingMemberAnnotation)
                                                .WithAdditionalAnnotations(Formatter.Annotation),
                                                out root, out model);
                containingMember = (MethodDeclarationSyntax)root.GetAnnotatedNodes(containingMemberAnnotation).Single();
                subjectNode      = root.GetAnnotatedNodes(subjectNodeAnnotation).Single();
                requestAsyncInvocationStatement = subjectNode.GetAncestorStatement();
                var eventHandlerStatementsSpan =
                    containingMember.GetSpanOfAssignmentDependenciesAndDeclarationsInSpan(requestAsyncInvocationStatement.FullSpan,
                                                                                          model);

                // Get catch block, and create error event handler
                // while ancestor parent is not try or member declaration, if try, check for correct catch.
                // if none found, throw
                {
                    var tryCandidate = requestAsyncInvocationStatement.Ancestors().First(e => e is BlockSyntax).Parent;
                    do
                    {
                        var tryStatement = tryCandidate as TryStatementSyntax;
                        if (tryStatement != null)
                        {
                            var exceptionType = typeof(ReceivedErrorEventException <>);
                            catchStatement = tryStatement.GetFirstCatchClauseByType(model, exceptionType, cancellationToken);
                            if (catchStatement != null)
                            {
                                var errorType = model.GetTypeInfo(catchStatement.Declaration.Type, cancellationToken).Type as INamedTypeSymbol;
                                // ReSharper disable once PossibleNullReferenceException
                                if (errorEventType.ToString().Equals(errorType.TypeArguments[0].ToString()))
                                {
                                    catchExceptionIdentifier = catchStatement.Declaration.Identifier;
                                    break;
                                }
                                catchStatement = null;
                            }
                        }
                        tryCandidate = tryCandidate.Parent;
                    } while (tryCandidate != null && !(tryCandidate is MemberDeclarationSyntax));

                    if (catchStatement == null)
                    {
                        throw new InvalidOperationException();
                    }

                    errorEventHandlerMessageParameterIdentifier = GenerateUniqueParameterIdentifierForScope(errorEventType, model,
                                                                                                            catchStatement.Block);
                    catchStatement = catchStatement.ReplaceNodes(
                        catchStatement.Block.DescendantNodes().Where(e => e is ExpressionSyntax),
                        (a, b) => Simplifier.Expand(a, model, document.Project.Solution.Workspace));

                    var firstStatement = catchStatement.Block.Statements.FirstOrDefault();
                    if (firstStatement != null)
                    {
                        catchStatement = catchStatement.ReplaceNode(firstStatement,
                                                                    firstStatement.WithLeadingTrivia(
                                                                        Comment("// TODO: Load message information from a repository by CorrelationId"),
                                                                        LineFeed));
                    }
                    else
                    {
                        catchStatement = catchStatement.WithBlock(catchStatement.Block.WithOpenBraceToken(
                                                                      Token(SyntaxKind.CloseBraceToken)
                                                                      .WithLeadingTrivia(Comment("// TODO: Load message information from a repository by CorrelationId"),
                                                                                         LineFeed)));
                    }

                    foreach (var statement in catchStatement.Block.DescendantNodes(_ => true)
                             .OfType <MemberAccessExpressionSyntax>()
                             .Where(a =>
                    {
                        var i = a.Expression as IdentifierNameSyntax;
                        return(i != null && i.Identifier.ValueText == catchExceptionIdentifier.ValueText);
                    })
                             .ToArray())
                    {
                        catchStatement = catchStatement.ReplaceNode(statement,
                                                                    IdentifierName(errorEventHandlerMessageParameterIdentifier));
                    }

                    document = document.ReplaceNode(tryCandidate, tryCandidate.WithAdditionalAnnotations(tryAnnotation), out root,
                                                    out model);
                }
                subjectNode = root.GetAnnotatedNodes(subjectNodeAnnotation).Single();
                requestAsyncInvocationStatement    = subjectNode.GetAncestorStatement();
                requestAsyncAndDependantStatements = root.DescendantNodes()
                                                     .OfType <StatementSyntax>()
                                                     .Where(x => eventHandlerStatementsSpan.Contains(x.Span) && x != requestAsyncInvocationStatement)
                                                     .ToArray();
                // expand in original document and add to block
                eventHandlerHandleMethodBody = Block(List(requestAsyncAndDependantStatements
                                                          .Select(e => Simplifier.Expand(e, model, document.Project.Solution.Workspace))
                                                          .ToArray()));
                eventHandlerHandleMethodBody = eventHandlerHandleMethodBody.ReplaceNode(eventHandlerHandleMethodBody.Statements.First(),
                                                                                        eventHandlerHandleMethodBody.Statements.First().WithLeadingTrivia(
                                                                                            Comment("// TODO: Load message information from a repository by CorrelationId"),
                                                                                            LineFeed));
            }

            var options = document.Project.Solution.Workspace.Options;
            var namespaceIdentifierName = IdentifierName(fullContainingNamespaceName);

            // start of modifications
            ClassDeclarationSyntax eventHandlerDeclaration;
            {
                #region create event handler declaration
                {
                    eventHandlerDeclaration = Utilities.MessageHandlerDeclaration(
                        eventType,
                        generator, eventHandlerHandleMethodBody,
                        handleMethodParameterName);

                    var ns = (NamespaceDeclarationSyntax)generator
                             .NamespaceDeclaration(namespaceIdentifierName)
                             .WithAdditionalAnnotations(Formatter.Annotation);

                    // create event handler document
                    var filename = eventHandlerDeclaration.Identifier.ValueText + ".cs";

                    // not thrilled about using text here, but some sort of disconnect between documents when
                    // we get to AddImports and Reduce otherwise.
                    var eventHandlerDocument = document.Project.AddDocument(filename,
                                                                            ns.AddMembers(eventHandlerDeclaration).NormalizeWhitespace().ToString());

                    eventHandlerDocument = await ImportAdder.AddImportsAsync(eventHandlerDocument, options, cancellationToken);

                    eventHandlerDocument = await Simplifier.ReduceAsync(eventHandlerDocument, options, cancellationToken);

                    eventHandlerDocument = await Formatter.FormatAsync(eventHandlerDocument, options, cancellationToken);

                    solution = eventHandlerDocument.Project.Solution.WithDocumentText(eventHandlerDocument.Id,
                                                                                      await eventHandlerDocument.GetTextAsync(cancellationToken));
                    document = solution.GetDocument(document.Id);
                    root     = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    model = await document.GetSemanticModelAsync(cancellationToken);
                }

                #endregion create event handler declaration

                // replace the call to RequestAsync and dependant statements with call to Sendr
                root = root.ReplaceNodes(requestAsyncAndDependantStatements,
                                         ExpressionStatement(
                                             InvocationExpression(
                                                 MemberAccessExpression(
                                                     SyntaxKind.SimpleMemberAccessExpression,
                                                     requestAsyncMemberAccess.Expression,                            // "bus"
                                                     IdentifierName(nameof(BusExtensions.Send))
                                                     .WithAdditionalAnnotations(subjectNodeAnnotation)))
                                             .WithArgumentList(((InvocationExpressionSyntax)requestAsyncMemberAccess.Parent).ArgumentList))
                                         .WithLeadingTrivia(
                                             Comment("// TODO: store information about the message with CorrelationId for loading in handlers"),
                                             CarriageReturnLineFeed));

                // remove async and change return type
                var containingMember = (MethodDeclarationSyntax)root.GetAnnotatedNodes(containingMemberAnnotation).Single();
                root = root.ReplaceNode(containingMember, containingMember.WithoutAsync()
                                        .WithAdditionalAnnotations(Formatter.Annotation));
                // remove try/catch
                var @try = root.DescendantNodes(_ => true).Single(e => e.HasAnnotation(tryAnnotation));
                root = root.RemoveNode(@try, SyntaxRemoveOptions.KeepExteriorTrivia);

                document = document.WithSyntaxRoot(root);
            }

            // error event handler class:
            ClassDeclarationSyntax errorEventHandlerDeclaration;
            {
                errorEventHandlerDeclaration = Utilities.MessageHandlerDeclaration(
                    errorEventType,
                    generator, catchStatement.Block,
                    errorEventHandlerMessageParameterIdentifier);
                var ns = (NamespaceDeclarationSyntax)generator
                         .NamespaceDeclaration(namespaceIdentifierName)
                         .WithAdditionalAnnotations(Formatter.Annotation);
                // create new document
                var errorEventHandlerDocument =
                    document.Project.AddDocument(errorEventHandlerDeclaration.Identifier.ValueText + ".cs",
                                                 ns.AddMembers(errorEventHandlerDeclaration).NormalizeWhitespace().ToString());
                document = errorEventHandlerDocument.Project.GetDocument(document.Id);

                errorEventHandlerDocument = await ImportAdder.AddImportsAsync(errorEventHandlerDocument, options, cancellationToken);

                errorEventHandlerDocument = await Simplifier.ReduceAsync(errorEventHandlerDocument, options, cancellationToken);

                errorEventHandlerDocument = await Formatter.FormatAsync(errorEventHandlerDocument,
                                                                        cancellationToken : cancellationToken);

                solution = errorEventHandlerDocument.Project.Solution.WithDocumentText(errorEventHandlerDocument.Id,
                                                                                       await errorEventHandlerDocument.GetTextAsync(cancellationToken));
            }
            {
                document = solution.GetDocument(document.Id);
                model    = await document.GetSemanticModelAsync(cancellationToken);

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

                // go looking for a reference to c'tor of a IBus type.
                var busSend = root.GetAnnotatedNodes(subjectNodeAnnotation).Single();
                requestAsyncMemberAccess =
                    busSend.Parent.AncestorsAndSelf()
                    .OfType <MemberAccessExpressionSyntax>()
                    .First();
                var busSymbol = model.GetTypeInfo(requestAsyncMemberAccess.Expression).Type as INamedTypeSymbol;
                Debug.Assert(busSymbol != null, "busSymbol != null");
                IMethodSymbol ctorSymbol;
                // ReSharper disable once PossibleNullReferenceException
                if (busSymbol.TypeKind == TypeKind.Interface)
                {
                    var busImplementations = await SymbolFinder.FindImplementationsAsync(busSymbol, solution,
                                                                                         cancellationToken : cancellationToken);

                    foreach (INamedTypeSymbol impl in busImplementations.OfType <INamedTypeSymbol>())
                    {
                        // only implementations with public constructors
                        ctorSymbol = impl.Constructors.SingleOrDefault(e => !e.IsStatic && e.Parameters.Length == 0);
                        if (ctorSymbol != null)
                        {
                            busSymbol = impl;
                            break;
                        }
                    }
                }
                ctorSymbol = busSymbol.Constructors.SingleOrDefault(e => !e.IsStatic && e.Parameters.Length == 0);
                var handlerSymbol = busSymbol.GetMembers(nameof(IBus.AddHandler)).Single();
                // ReSharper disable once PossibleUnintendedReferenceComparison
                if (handlerSymbol != default(ISymbol))
                {
                    var references = (await SymbolFinder.FindReferencesAsync(handlerSymbol,
                                                                             solution, cancellationToken)).ToArray();
                    if (references.Any(e => e.Locations.Any()))
                    {
                        // TODO: add AddHandlers at this location
                        var definition = references
                                         .GroupBy(e => e.Definition)
                                         .OrderByDescending(g => g.Count())
                                         .First();
                    }
                    else
                    {
                        // no add handlers at the moment, let's just find where it was constructed.
                        var locations =
                            (await SymbolFinder.FindReferencesAsync(ctorSymbol, solution, cancellationToken))
                            .SelectMany(e => e.Locations).ToArray();
                        if (locations.Length != 0)
                        {
                            var referencedLocation = locations.First();
                            {
                                var referencedLocationDocument = referencedLocation.Document;
                                var referencedRoot             = await referencedLocationDocument.GetSyntaxRootAsync(cancellationToken);

                                var node        = referencedRoot.FindNode(referencedLocation.Location.SourceSpan);
                                var statement   = node.GetAncestorStatement();
                                var busNode     = statement.GetAssignmentToken().WithLeadingTrivia().WithTrailingTrivia();
                                var busNodeName = IdentifierName(busNode);
                                if (busNodeName != null)
                                {
                                    var errorEventHandlerName =
                                        IdentifierName(errorEventHandlerDeclaration.Identifier);
                                    referencedLocationDocument = InsertAddHandlerCall(
                                        referencedLocationDocument,
                                        referencedLocation, busNodeName, errorEventHandlerName);
                                    var eventHandlerName =
                                        IdentifierName(eventHandlerDeclaration.Identifier);
                                    referencedLocationDocument = InsertAddHandlerCall(
                                        referencedLocationDocument,
                                        referencedLocation, busNodeName, eventHandlerName);
                                    solution = referencedLocationDocument.Project.Solution;
                                }
                            }
                        }
                    }
                }
                return(solution);
            }
        }