private bool AnalyzeMemberWithinContext(ITypeSymbol type, ISymbol?symbol, SyntaxNodeAnalysisContext context, Location?focusDiagnosticOn = null)
            {
                if (type is null)
                {
                    throw new ArgumentNullException(nameof(type));
                }

                bool requiresUIThread = (type.TypeKind == TypeKind.Interface || type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct) &&
                                        this.MembersRequiringMainThread.Contains(type, symbol);

                if (requiresUIThread)
                {
                    ThreadingContext threadingContext  = ThreadingContext.Unknown;
                    SyntaxNode?      methodDeclaration = context.Node.FirstAncestorOrSelf <SyntaxNode>(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind()));
                    if (methodDeclaration is object)
                    {
                        threadingContext = this.methodDeclarationNodes.GetValueOrDefault(methodDeclaration);
                    }

                    if (threadingContext != ThreadingContext.MainThread)
                    {
                        CSharpUtils.ContainingFunctionData function = CSharpUtils.GetContainingFunction((CSharpSyntaxNode)context.Node);
                        Location             location   = focusDiagnosticOn ?? context.Node.GetLocation();
                        DiagnosticDescriptor?descriptor = function.IsAsync ? DescriptorAsync : DescriptorSync;
                        var formattingArgs = function.IsAsync ? new object[] { type.Name } : new object[] { type.Name, this.MainThreadAssertingMethods.FirstOrDefault() };
                        context.ReportDiagnostic(Diagnostic.Create(descriptor, location, this.DiagnosticProperties, formattingArgs));
                        return(true);
                    }
                }

                return(false);
            }
        private void AddToCallerCalleeMap(OperationAnalysisContext context, Dictionary <IMethodSymbol, List <CallInfo> > callerToCalleeMap)
        {
            if (CSharpUtils.IsWithinNameOf(context.Operation.Syntax))
            {
                return;
            }

            IMethodSymbol?GetPropertyAccessor(IPropertySymbol?propertySymbol)
            {
                if (propertySymbol is object)
                {
                    return(CSharpUtils.IsOnLeftHandOfAssignment(context.Operation.Syntax)
                        ? propertySymbol.SetMethod
                        : propertySymbol.GetMethod);
                }

                return(null);
            }

            ISymbol?   targetMethod    = null;
            SyntaxNode locationToBlame = context.Operation.Syntax;

            switch (context.Operation)
            {
            case IInvocationOperation invocationOperation:
                targetMethod    = invocationOperation.TargetMethod;
                locationToBlame = this.languageUtils.IsolateMethodName(invocationOperation);
                break;

            case IPropertyReferenceOperation propertyReference:
                targetMethod = GetPropertyAccessor(propertyReference.Property);
                break;

            case IEventAssignmentOperation eventAssignmentOperation:
                IOperation eventReferenceOp = eventAssignmentOperation.EventReference;
                if (eventReferenceOp is IEventReferenceOperation eventReference)
                {
                    targetMethod = eventAssignmentOperation.Adds
                            ? eventReference.Event.AddMethod
                            : eventReference.Event.RemoveMethod;
                    locationToBlame = eventReference.Syntax;
                }

                break;
            }

            if (context.ContainingSymbol is IMethodSymbol caller && targetMethod is IMethodSymbol callee)
            {
                lock (callerToCalleeMap)
                {
                    if (!callerToCalleeMap.TryGetValue(caller, out List <CallInfo> callees))
                    {
                        callerToCalleeMap[caller] = callees = new List <CallInfo>();
                    }

                    callees.Add(new CallInfo(methodSymbol: callee, invocationSyntax: locationToBlame));
                }
            }
        }
Ejemplo n.º 3
0
        internal static void InspectMemberAccess(
            SyntaxNodeAnalysisContext context,
            MemberAccessExpressionSyntax?memberAccessSyntax,
            DiagnosticDescriptor descriptor,
            IEnumerable <CommonInterest.SyncBlockingMethod> problematicMethods,
            bool ignoreIfInsideAnonymousDelegate = false)
        {
            if (descriptor is null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            if (memberAccessSyntax is null)
            {
                return;
            }

            if (ShouldIgnoreContext(context))
            {
                return;
            }

            if (ignoreIfInsideAnonymousDelegate && context.Node.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>() is object)
            {
                // We do not analyze JTF.Run inside anonymous functions because
                // they are so often used as callbacks where the signature is constrained.
                return;
            }

            if (CSharpUtils.IsWithinNameOf(context.Node as ExpressionSyntax))
            {
                // We do not consider arguments to nameof( ) because they do not represent invocations of code.
                return;
            }

            ITypeSymbol?typeReceiver = context.SemanticModel.GetTypeInfo(memberAccessSyntax.Expression).Type;

            if (typeReceiver is object)
            {
                foreach (CommonInterest.SyncBlockingMethod item in problematicMethods)
                {
                    if (memberAccessSyntax.Name.Identifier.Text == item.Method.Name &&
                        typeReceiver.Name == item.Method.ContainingType.Name &&
                        typeReceiver.BelongsToNamespace(item.Method.ContainingType.Namespace))
                    {
                        if (HasTaskCompleted(context, memberAccessSyntax))
                        {
                            return;
                        }

                        Location?location = memberAccessSyntax.Name.GetLocation();
                        context.ReportDiagnostic(Diagnostic.Create(descriptor, location));
                    }
                }
            }
        }
Ejemplo n.º 4
0
            internal void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
            {
                if (IsInTaskReturningMethodOrDelegate(context))
                {
                    var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node;
                    var memberAccessSyntax         = invocationExpressionSyntax.Expression as MemberAccessExpressionSyntax;
                    if (InspectMemberAccess(context, memberAccessSyntax, CommonInterest.SyncBlockingMethods))
                    {
                        // Don't return double-diagnostics.
                        return;
                    }

                    MethodDeclarationSyntax invocationDeclaringMethod = invocationExpressionSyntax.FirstAncestorOrSelf <MethodDeclarationSyntax>();

                    // Also consider all method calls to check for Async-suffixed alternatives.
                    ExpressionSyntax invokedMethodName = CSharpUtils.IsolateMethodName(invocationExpressionSyntax);
                    var symbolInfo   = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax, context.CancellationToken);
                    var methodSymbol = symbolInfo.Symbol as IMethodSymbol;
                    if (methodSymbol != null && !methodSymbol.Name.EndsWith(VSTHRD200UseAsyncNamingConventionAnalyzer.MandatoryAsyncSuffix) &&
                        !(methodSymbol.ReturnType?.Name == nameof(Task) && methodSymbol.ReturnType.BelongsToNamespace(Namespaces.SystemThreadingTasks)))
                    {
                        string asyncMethodName = methodSymbol.Name + VSTHRD200UseAsyncNamingConventionAnalyzer.MandatoryAsyncSuffix;
                        var    symbols         = context.SemanticModel.LookupSymbols(
                            invocationExpressionSyntax.Expression.GetLocation().SourceSpan.Start,
                            methodSymbol.ContainingType,
                            asyncMethodName,
                            includeReducedExtensionMethods: true);

                        foreach (var s in symbols)
                        {
                            if (s is IMethodSymbol m &&
                                !m.IsObsolete() &&
                                HasSupersetOfParameterTypes(m, methodSymbol) &&
                                m.Name != invocationDeclaringMethod?.Identifier.Text &&
                                Utils.HasAsyncCompatibleReturnType(m))
                            {
                                // An async alternative exists.
                                var properties = ImmutableDictionary <string, string> .Empty
                                                 .Add(AsyncMethodKeyName, asyncMethodName);

                                Diagnostic diagnostic = Diagnostic.Create(
                                    Descriptor,
                                    invokedMethodName.GetLocation(),
                                    properties,
                                    invokedMethodName.ToString(),
                                    asyncMethodName);
                                context.ReportDiagnostic(diagnostic);

                                return;
                            }
                        }
                    }
                }
            }
Ejemplo n.º 5
0
        private static void AddToCallerCalleeMap(SyntaxNodeAnalysisContext context, Dictionary <IMethodSymbol, List <CallInfo> > callerToCalleeMap)
        {
            if (CSharpUtils.IsWithinNameOf(context.Node))
            {
                return;
            }

            IMethodSymbol?GetPropertyAccessor(IPropertySymbol?propertySymbol)
            {
                if (propertySymbol is object)
                {
                    return(CSharpUtils.IsOnLeftHandOfAssignment(context.Node)
                        ? propertySymbol.SetMethod
                        : propertySymbol.GetMethod);
                }

                return(null);
            }

            ISymbol?   targetMethod    = null;
            SyntaxNode locationToBlame = context.Node;

            switch (context.Node)
            {
            case InvocationExpressionSyntax invocationExpressionSyntax:
                targetMethod    = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax.Expression, context.CancellationToken).Symbol;
                locationToBlame = invocationExpressionSyntax.Expression;
                break;

            case MemberAccessExpressionSyntax memberAccessExpressionSyntax:
                targetMethod = GetPropertyAccessor(context.SemanticModel.GetSymbolInfo(memberAccessExpressionSyntax.Name, context.CancellationToken).Symbol as IPropertySymbol);
                break;

            case IdentifierNameSyntax identifierNameSyntax:
                targetMethod = GetPropertyAccessor(context.SemanticModel.GetSymbolInfo(identifierNameSyntax, context.CancellationToken).Symbol as IPropertySymbol);
                break;
            }

            if (context.ContainingSymbol is IMethodSymbol caller && targetMethod is IMethodSymbol callee)
            {
                lock (callerToCalleeMap)
                {
                    if (!callerToCalleeMap.TryGetValue(caller, out List <CallInfo> callees))
                    {
                        callerToCalleeMap[caller] = callees = new List <CallInfo>();
                    }

                    callees.Add(new CallInfo(methodSymbol: callee, invocationSyntax: locationToBlame));
                }
            }
        }
        private void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
        {
            var invocationExpressionSyntax     = (InvocationExpressionSyntax)context.Node;
            ExpressionSyntax invokedMethodName = CSharpUtils.IsolateMethodName(invocationExpressionSyntax);
            var argList      = invocationExpressionSyntax.ArgumentList;
            var symbolInfo   = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax, context.CancellationToken);
            var methodSymbol = symbolInfo.Symbol as IMethodSymbol;

            // nameof(X) has no method symbol. So skip over such.
            if (methodSymbol != null)
            {
                var otherOverloads = methodSymbol.ContainingType.GetMembers(methodSymbol.Name).OfType <IMethodSymbol>();
                AnalyzeCall(context, invokedMethodName.GetLocation(), argList, methodSymbol, otherOverloads);
            }
        }
            internal void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
            {
                var invocation = (InvocationExpressionSyntax)context.Node;

                // Only consider invocations that are direct statements. Otherwise, we assume their
                // result is awaited, assigned, or otherwise consumed.
                if (invocation.Parent is ExpressionStatementSyntax || invocation.Parent is ConditionalAccessExpressionSyntax)
                {
                    var methodSymbol = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IMethodSymbol;
                    if (this.IsAwaitableType(methodSymbol?.ReturnType, context.Compilation, context.CancellationToken))
                    {
                        if (!CSharpUtils.GetContainingFunction(invocation).IsAsync)
                        {
                            Location?location = (CSharpUtils.IsolateMethodName(invocation) ?? invocation.Expression).GetLocation();
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                        }
                    }
                }
            }
        private void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax)context.Node;

            // Only consider invocations that are direct statements. Otherwise, we assume their
            // result is awaited, assigned, or otherwise consumed.
            if (invocation.Parent?.GetType().Equals(typeof(ExpressionStatementSyntax)) ?? false)
            {
                var methodSymbol   = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IMethodSymbol;
                var returnedSymbol = methodSymbol?.ReturnType;
                if (returnedSymbol?.Name == Types.Task.TypeName && returnedSymbol.BelongsToNamespace(Types.Task.Namespace))
                {
                    if (!CSharpUtils.GetContainingFunction(invocation).IsAsync)
                    {
                        var location = (CSharpUtils.IsolateMethodName(invocation) ?? invocation.Expression).GetLocation();
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                    }
                }
            }
        }
Ejemplo n.º 9
0
            private void InspectMemberAccess(SyntaxNodeAnalysisContext context, MemberAccessExpressionSyntax?memberAccessSyntax, IEnumerable <CommonInterest.SyncBlockingMethod> problematicMethods)
            {
                if (memberAccessSyntax is null)
                {
                    return;
                }

                if (this.diagnosticReported)
                {
                    // Don't report more than once per method.
                    return;
                }

                if (context.Node.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>() is object)
                {
                    // We do not analyze JTF.Run inside anonymous functions because
                    // they are so often used as callbacks where the signature is constrained.
                    return;
                }

                if (CSharpUtils.IsWithinNameOf(context.Node as ExpressionSyntax))
                {
                    // We do not consider arguments to nameof( ) because they do not represent invocations of code.
                    return;
                }

                ISymbol?invokedMember = context.SemanticModel.GetSymbolInfo(memberAccessSyntax, context.CancellationToken).Symbol;

                if (invokedMember is object)
                {
                    foreach (CommonInterest.SyncBlockingMethod item in problematicMethods)
                    {
                        if (item.Method.IsMatch(invokedMember))
                        {
                            Location?location = memberAccessSyntax.Name.GetLocation();
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                            this.diagnosticReported = true;
                        }
                    }
                }
            }
Ejemplo n.º 10
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic?diagnostic = context.Diagnostics.First();

            SyntaxNode?root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            var syntaxNode = (ExpressionSyntax)root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);

            CSharpUtils.ContainingFunctionData container = CSharpUtils.GetContainingFunction(syntaxNode);
            if (container.BlockOrExpression is null)
            {
                return;
            }

            SemanticModel?semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

            ISymbol?enclosingSymbol = semanticModel.GetEnclosingSymbol(diagnostic.Location.SourceSpan.Start, context.CancellationToken);

            if (enclosingSymbol is null)
            {
                return;
            }

            bool convertToAsync = !container.IsAsync && Utils.HasAsyncCompatibleReturnType(enclosingSymbol as IMethodSymbol);

            if (convertToAsync)
            {
                // We don't support this yet, and we don't want to take the sync method path in this case.
                // The user will have to fix this themselves.
                return;
            }

            Regex lookupKey = (container.IsAsync || convertToAsync)
                ? CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread
                : CommonInterest.FileNamePatternForMethodsThatAssertMainThread;

            string[] options = diagnostic.Properties[lookupKey.ToString()].Split('\n');
            if (options.Length > 0)
            {
                // For any symbol lookups, we want to consider the position of the very first statement in the block.
                int positionForLookup = container.BlockOrExpression.GetLocation().SourceSpan.Start + 1;

                Lazy <ISymbol> cancellationTokenSymbol = new Lazy <ISymbol>(() => Utils.FindCancellationToken(semanticModel, positionForLookup, context.CancellationToken).FirstOrDefault());
                foreach (var option in options)
                {
                    // We're looking for methods that either require no parameters,
                    // or (if we have one to give) that have just one parameter that is a CancellationToken.
                    IMethodSymbol?proposedMethod = Utils.FindMethodGroup(semanticModel, option)
                                                   .FirstOrDefault(m => !m.Parameters.Any(p => !p.HasExplicitDefaultValue) ||
                                                                   (cancellationTokenSymbol.Value is object && m.Parameters.Length == 1 && Utils.IsCancellationTokenParameter(m.Parameters[0])));
                    if (proposedMethod is null)
                    {
                        // We can't find it, so don't offer to use it.
                        continue;
                    }

                    if (proposedMethod.IsStatic)
                    {
                        OfferFix(option);
                    }
                    else
                    {
                        foreach (Tuple <bool, ISymbol>?candidate in Utils.FindInstanceOf(proposedMethod.ContainingType, semanticModel, positionForLookup, context.CancellationToken))
                        {
                            if (candidate.Item1)
                            {
                                OfferFix($"{candidate.Item2.Name}.{proposedMethod.Name}");
                            }
                            else
                            {
                                OfferFix($"{candidate.Item2.ContainingNamespace}.{candidate.Item2.ContainingType.Name}.{candidate.Item2.Name}.{proposedMethod.Name}");
                            }
                        }
                    }

                    void OfferFix(string fullyQualifiedMethod)
                    {
                        context.RegisterCodeFix(CodeAction.Create($"Add call to {fullyQualifiedMethod}", ct => Fix(fullyQualifiedMethod, proposedMethod, cancellationTokenSymbol), fullyQualifiedMethod), context.Diagnostics);
                    }
                }
            }

            Task <Document> Fix(string fullyQualifiedMethod, IMethodSymbol methodSymbol, Lazy <ISymbol> cancellationTokenSymbol)
            {
                int typeAndMethodDelimiterIndex                       = fullyQualifiedMethod.LastIndexOf('.');
                IdentifierNameSyntax       methodName                 = SyntaxFactory.IdentifierName(fullyQualifiedMethod.Substring(typeAndMethodDelimiterIndex + 1));
                ExpressionSyntax           invokedMethod              = CSharpUtils.MemberAccess(fullyQualifiedMethod.Substring(0, typeAndMethodDelimiterIndex).Split('.'), methodName);
                InvocationExpressionSyntax?invocationExpression       = SyntaxFactory.InvocationExpression(invokedMethod);
                IParameterSymbol?          cancellationTokenParameter = methodSymbol.Parameters.FirstOrDefault(Utils.IsCancellationTokenParameter);

                if (cancellationTokenParameter is object && cancellationTokenSymbol.Value is object)
                {
                    ArgumentSyntax?arg = SyntaxFactory.Argument(SyntaxFactory.IdentifierName(cancellationTokenSymbol.Value.Name));
                    if (methodSymbol.Parameters.IndexOf(cancellationTokenParameter) > 0)
                    {
                        arg = arg.WithNameColon(SyntaxFactory.NameColon(SyntaxFactory.IdentifierName(cancellationTokenParameter.Name)));
                    }

                    invocationExpression = invocationExpression.AddArgumentListArguments(arg);
                }

                ExpressionSyntax?         awaitExpression = container.IsAsync ? SyntaxFactory.AwaitExpression(invocationExpression) : null;
                ExpressionStatementSyntax?addedStatement  = SyntaxFactory.ExpressionStatement(awaitExpression ?? invocationExpression)
                                                            .WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation);
                var initialBlockSyntax = container.BlockOrExpression as BlockSyntax;

                if (initialBlockSyntax is null)
                {
                    SyntaxToken openBrace  = SyntaxFactory.Token(SyntaxFactory.TriviaList(), SyntaxKind.OpenBraceToken, SyntaxFactory.TriviaList(SyntaxFactory.EndOfLine("\r\n")));
                    SyntaxToken closeBrace = SyntaxFactory.Token(SyntaxKind.CloseBraceToken);
                    SyntaxList <StatementSyntax> statementList = SyntaxFactory.List <StatementSyntax>(new[] { SyntaxFactory.ReturnStatement((ExpressionSyntax)container.BlockOrExpression) });
                    initialBlockSyntax = SyntaxFactory.Block(openBrace, statementList, closeBrace)
                                         .WithAdditionalAnnotations(Formatter.Annotation);
                }

                BlockSyntax?newBlock = initialBlockSyntax.WithStatements(initialBlockSyntax.Statements.Insert(0, addedStatement));

                return(Task.FromResult(context.Document.WithSyntaxRoot(root.ReplaceNode(container.BlockOrExpression.Parent, container.BodyReplacement(newBlock)))));
            }
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            foreach (var diagnostic in context.Diagnostics)
            {
                var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

                ExpressionSyntax?syntaxNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) as ExpressionSyntax;
                if (syntaxNode is null)
                {
                    continue;
                }

                var container = CSharpUtils.GetContainingFunction(syntaxNode);
                if (container.BlockOrExpression == null)
                {
                    return;
                }

                if (!container.IsAsync)
                {
                    if (!(container.Function is MethodDeclarationSyntax || container.Function is AnonymousFunctionExpressionSyntax))
                    {
                        // We don't support converting whatever this is into an async method.
                        return;
                    }
                }

                var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

                var enclosingSymbol = semanticModel.GetEnclosingSymbol(diagnostic.Location.SourceSpan.Start, context.CancellationToken);
                if (enclosingSymbol == null)
                {
                    return;
                }

                var hasReturnValue = ((enclosingSymbol as IMethodSymbol)?.ReturnType as INamedTypeSymbol)?.IsGenericType ?? false;
                var options        = await CommonFixes.ReadMethodsAsync(context, CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread, context.CancellationToken);

                int     positionForLookup       = diagnostic.Location.SourceSpan.Start;
                ISymbol cancellationTokenSymbol = Utils.FindCancellationToken(semanticModel, positionForLookup, context.CancellationToken).FirstOrDefault();
                foreach (var option in options)
                {
                    // We're looking for methods that either require no parameters,
                    // or (if we have one to give) that have just one parameter that is a CancellationToken.
                    var proposedMethod = Utils.FindMethodGroup(semanticModel, option)
                                         .FirstOrDefault(m => !m.Parameters.Any(p => !p.HasExplicitDefaultValue) ||
                                                         (cancellationTokenSymbol != null && m.Parameters.Length == 1 && Utils.IsCancellationTokenParameter(m.Parameters[0])));
                    if (proposedMethod == null)
                    {
                        // We can't find it, so don't offer to use it.
                        continue;
                    }

                    if (proposedMethod.IsStatic)
                    {
                        OfferFix(option.ToString());
                    }
                    else
                    {
                        foreach (var candidate in Utils.FindInstanceOf(proposedMethod.ContainingType, semanticModel, positionForLookup, context.CancellationToken))
                        {
                            if (candidate.Item1)
                            {
                                OfferFix($"{candidate.Item2.Name}.{proposedMethod.Name}");
                            }
                            else
                            {
                                OfferFix($"{candidate.Item2.ContainingNamespace}.{candidate.Item2.ContainingType.Name}.{candidate.Item2.Name}.{proposedMethod.Name}");
                            }
                        }
                    }

                    void OfferFix(string fullyQualifiedMethod)
                    {
                        context.RegisterCodeFix(CodeAction.Create($"Use 'await {fullyQualifiedMethod}'", ct => Fix(fullyQualifiedMethod, proposedMethod, hasReturnValue, ct), fullyQualifiedMethod), context.Diagnostics);
                    }
                }

                async Task <Solution> Fix(string fullyQualifiedMethod, IMethodSymbol methodSymbol, bool hasReturnValue, CancellationToken cancellationToken)
                {
                    var assertionStatementToRemove = syntaxNode !.FirstAncestorOrSelf <StatementSyntax>();

                    int typeAndMethodDelimiterIndex    = fullyQualifiedMethod.LastIndexOf('.');
                    IdentifierNameSyntax methodName    = SyntaxFactory.IdentifierName(fullyQualifiedMethod.Substring(typeAndMethodDelimiterIndex + 1));
                    ExpressionSyntax     invokedMethod = CSharpUtils.MemberAccess(fullyQualifiedMethod.Substring(0, typeAndMethodDelimiterIndex).Split('.'), methodName)
                                                         .WithAdditionalAnnotations(Simplifier.Annotation);
                    var invocationExpression       = SyntaxFactory.InvocationExpression(invokedMethod);
                    var cancellationTokenParameter = methodSymbol.Parameters.FirstOrDefault(Utils.IsCancellationTokenParameter);

                    if (cancellationTokenParameter != null && cancellationTokenSymbol != null)
                    {
                        var arg = SyntaxFactory.Argument(SyntaxFactory.IdentifierName(cancellationTokenSymbol.Name));
                        if (methodSymbol.Parameters.IndexOf(cancellationTokenParameter) > 0)
                        {
                            arg = arg.WithNameColon(SyntaxFactory.NameColon(SyntaxFactory.IdentifierName(cancellationTokenParameter.Name)));
                        }

                        invocationExpression = invocationExpression.AddArgumentListArguments(arg);
                    }

                    ExpressionSyntax awaitExpression = SyntaxFactory.AwaitExpression(invocationExpression);
                    var addedStatement = SyntaxFactory.ExpressionStatement(awaitExpression)
                                         .WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation);

                    var methodAnnotation          = new SyntaxAnnotation();
                    CSharpSyntaxNode methodSyntax = container.Function.ReplaceNode(assertionStatementToRemove, addedStatement)
                                                    .WithAdditionalAnnotations(methodAnnotation);
                    Document newDocument   = context.Document.WithSyntaxRoot(root.ReplaceNode(container.Function, methodSyntax));
                    var      newSyntaxRoot = await newDocument.GetSyntaxRootAsync(cancellationToken);

                    methodSyntax = (CSharpSyntaxNode)newSyntaxRoot.GetAnnotatedNodes(methodAnnotation).Single();
                    if (!container.IsAsync)
                    {
                        switch (methodSyntax)
                        {
                        case AnonymousFunctionExpressionSyntax anonFunc:
                            semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken);

                            methodSyntax = FixUtils.MakeMethodAsync(anonFunc, hasReturnValue, semanticModel, cancellationToken);
                            newDocument  = newDocument.WithSyntaxRoot(newSyntaxRoot.ReplaceNode(anonFunc, methodSyntax));
                            break;

                        case MethodDeclarationSyntax methodDecl:
                            (newDocument, methodSyntax) = await FixUtils.MakeMethodAsync(methodDecl, newDocument, cancellationToken);

                            break;
                        }
                    }

                    return(newDocument.Project.Solution);
                }
            }
        }