public static CompilationUnitSyntax RefactorSimpleLambdaInstance(CompilationUnitSyntax syntax, InvocationExpressionSyntax apmSyntax, IMethodSymbol apmSymbol, SimpleLambdaExpressionSyntax lambda) { if (lambda.Body.CSharpKind() != SyntaxKind.Block) throw new NotImplementedException("Lambda body must be rewritten as BlockSyntax - it is now: " + lambda.Body.CSharpKind() + ": lambda: " + lambda); var lambdaBlock = (BlockSyntax)lambda.Body; var originatingMethodSyntax = apmSyntax.FirstAncestorOrSelf<MethodDeclarationSyntax>(); // TODO: This precondition'i Analyzer'a koy!!! if (originatingMethodSyntax == null || !originatingMethodSyntax.ReturnsVoid()) { throw new Exception("PRECONDITION: Initiating method does not return void"); } // TODO: Look up the symbol to check that it actually exists. var methodNameBase = GetAsyncMethodNameBase(apmSyntax); var endStatement = TryFindEndAPMCallSyntaxNode(lambdaBlock, methodNameBase); if (endStatement != null) { return RewriteNotNestedInstance(syntax, originatingMethodSyntax, apmSyntax, lambdaBlock, endStatement, methodNameBase, ); } // Every method invocation might lead to the target EndXxx. Try to find it recursively. // Once found, rewrite the methods in the invocation path, one by one. // Finally, rewrite the originating method, and the method with the EndXxx statement. var invocationPathToEndXxx = TryFindCallGraphPathToEndXxx(lambdaBlock, methodNameBase, model); if (invocationPathToEndXxx.Count == 0) { throw new PreconditionException("Could not find End call in lambda body call graph"); } // These two get special treatment. var initialCall = invocationPathToEndXxx.RemoveLast(); var endXxxCall = invocationPathToEndXxx.RemoveFirst(); IMethodSymbol endXxxMethod; try { endXxxMethod = model.LookupMethodSymbol(endXxxCall); } catch (SymbolMissingException e) { Logger.Error("No symbol found for APM End invocation: {0}", endXxxCall, e); throw new RefactoringException("No symbol found for APM End invocation: " + endXxxCall, e); } var taskTypeParameter = endXxxMethod.ReturnType.Name; var replacements = new List<SyntaxReplacementPair>(invocationPathToEndXxx.Count + 2); // Replace all intermediate methods on the call graph path. replacements.AddRange( invocationPathToEndXxx.Select( invocation => new SyntaxReplacementPair( invocation.ContainingMethod(), RewriteCallGraphPathComponent(invocation, taskTypeParameter) ) ) ); // Replace method that contains BeginXxx call. var taskName = FreeTaskName(originatingMethodSyntax); replacements.Add( new SyntaxReplacementPair( originatingMethodSyntax, RewriteOriginatingMethod( apmSyntax, RewriteOriginatingMethodLambdaBlock(lambda, initialCall, taskName), methodNameBase, taskName ) ) ); // Replace method that contains the EndXxx call. replacements.Add( new SyntaxReplacementPair( endXxxCall.ContainingMethod(), RewriteEndXxxContainingMethod( endXxxCall, taskTypeParameter ) ) ); return syntax .ReplaceAll(replacements) .WithUsingSystemThreadingTasks() .Format(workspace); }