public IEnumerable<SyntaxTree> Rewrite(SyntaxTree[] syntaxTrees, CSharpCompilation compilationNode, string[] excludeTypes = null) { this.methodAttributesSymbol = compilationNode.GetTypeByMetadataName(typeof(MethodAttributes).FullName); this.cancellationTokenSymbol = compilationNode.GetTypeByMetadataName(typeof(CancellationToken).FullName); this.excludedTypes = new HashSet<ITypeSymbol>(); if (excludeTypes != null) { var excludedTypeSymbols = excludeTypes.Select(compilationNode.GetTypeByMetadataName).ToList(); var notFound = excludedTypeSymbols.IndexOf(null); if (notFound != -1) { throw new ArgumentException($"Type {excludeTypes[notFound]} not found in compilation", nameof(excludeTypes)); } this.excludedTypes.UnionWith(excludedTypeSymbols); } this.excludedTypes.UnionWith(alwaysExcludedTypeNames.Select(compilationNode.GetTypeByMetadataName).Where(sym => sym != null)); foreach (var syntaxTree in syntaxTrees) { var semanticModel = compilationNode.GetSemanticModel(syntaxTree, true); if (semanticModel == null) { throw new ArgumentException("A provided syntax tree was compiled into the provided compilation"); } var asyncMethods = syntaxTree .GetRoot() .DescendantNodes() .OfType<MethodDeclarationSyntax>() .Where(m => m.Modifiers.Any(c => c.Kind() == SyntaxKind.AsyncKeyword)); foreach (var asyncMethod in asyncMethods) { ValidateAsyncMethod(asyncMethod, semanticModel); } if (syntaxTree.GetRoot().DescendantNodes().All(m => ((m as MethodDeclarationSyntax)?.AttributeLists ?? (m as TypeDeclarationSyntax)?.AttributeLists)?.SelectMany(al => al.Attributes).Any(a => a.Name.ToString().StartsWith("RewriteAsync")) == null)) { continue; } var namespaces = SyntaxFactory.List<MemberDeclarationSyntax> ( syntaxTree.GetRoot() .DescendantNodes() .OfType<MethodDeclarationSyntax>() .Where(m => (m.Parent as TypeDeclarationSyntax)?.AttributeLists.SelectMany(al => al.Attributes).Any(a => a.Name.ToString().StartsWith("RewriteAsync")) == true || m.AttributeLists.SelectMany(al => al.Attributes).Any(a => a.Name.ToString().StartsWith("RewriteAsync"))) .Where(c => (c.FirstAncestorOrSelf<ClassDeclarationSyntax>() as TypeDeclarationSyntax ?? c.FirstAncestorOrSelf<InterfaceDeclarationSyntax>() as TypeDeclarationSyntax) != null) .GroupBy(m => m.FirstAncestorOrSelf<ClassDeclarationSyntax>() as TypeDeclarationSyntax ?? m.FirstAncestorOrSelf<InterfaceDeclarationSyntax>()) .GroupBy(g => g.Key.FirstAncestorOrSelf<NamespaceDeclarationSyntax>()) .Select(namespaceGrouping => SyntaxFactory.NamespaceDeclaration(namespaceGrouping.Key.Name) .WithMembers(SyntaxFactory.List<MemberDeclarationSyntax> ( namespaceGrouping.Select ( typeGrouping => typeGrouping.Key is ClassDeclarationSyntax ? SyntaxFactory.ClassDeclaration(typeGrouping.Key.Identifier).WithModifiers(typeGrouping.Key.Modifiers) .WithTypeParameterList(typeGrouping.Key.TypeParameterList) .WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>(typeGrouping.SelectMany(m => this.RewriteMethods(m, semanticModel)))) as TypeDeclarationSyntax : SyntaxFactory.InterfaceDeclaration(typeGrouping.Key.Identifier).WithModifiers(typeGrouping.Key.Modifiers) .WithTypeParameterList(typeGrouping.Key.TypeParameterList) .WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>(typeGrouping.SelectMany(m => this.RewriteMethods(m, semanticModel)))) as TypeDeclarationSyntax ) )) ) ); yield return SyntaxFactory.SyntaxTree ( SyntaxFactory.CompilationUnit() .WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>(namespaces.OfType<NamespaceDeclarationSyntax>().Select(c => AmendUsings(c, syntaxTree.GetCompilationUnitRoot().Usings)))) .WithEndOfFileToken(SyntaxFactory.Token(SyntaxKind.EndOfFileToken)) ); } }