public void GroupByDeclaration()
        {
            var c = CompilationHelper.Compile(@"using System.Text;
using TextTemplate;

partial class A
{
    [Template("""")]
    public partial void M1(StringBuilder builder);

    [Template("""")]
    public partial void M2(StringBuilder builder);
}

partial class A
{
    [Template("""")]
    private partial void M3(StringBuilder builder);

    [Template("""")]
    private partial void M4(StringBuilder builder);
}

partial class B
{
    [Template("""")]
    internal partial void M(StringBuilder builder);
}
", new TextTemplatePreprocessor());

            Assert.Empty(c.GetDiagnostics());
            Assert.Equal(5, c.SyntaxTrees.Count());
        }
        public void EmptyTemplate()
        {
            var c = CompilationHelper.Compile(@"using System.Text;
using TextTemplate;

partial class A
{
    [Template("""")]
    public partial void M(StringBuilder builder);
}", new TextTemplatePreprocessor());

            Assert.Empty(c.GetDiagnostics());

            var tree = c.SyntaxTrees.First(t => t.FilePath.EndsWith("A.M.cs"));

            Assert.True(tree.IsEquivalentTo(SyntaxFactory.ParseSyntaxTree(@"#pragma warning 8019
using System.Text;
using TextTemplate;
partial class A
{
public partial void M(StringBuilder builder)
{

}
}
")));
        }
        public void NoTemplates()
        {
            var c = CompilationHelper.Compile("class A { }", new TextTemplatePreprocessor());

            Assert.Empty(c.GetDiagnostics());
            Assert.Equal(2, c.SyntaxTrees.Count());
        }
        public void Template2()
        {
            var c = CompilationHelper.Compile(@"
partial class A
{
    [TextTemplate.Template(@""$<
void a(object x) => builder.Append(x);
$>($x, $y)"", ""a"")]
    public partial void M(System.Text.StringBuilder builder, object x, object y);
}", new TextTemplatePreprocessor());

            Assert.Empty(c.GetDiagnostics());

            var tree = c.SyntaxTrees.First(t => t.FilePath.EndsWith("A.M.cs"));

            Assert.True(tree.IsEquivalentTo(SyntaxFactory.ParseSyntaxTree(@"#pragma warning 8019
partial class A
{
public partial void M(System.Text.StringBuilder builder, object x, object y)
{

void a(object x) => builder.Append(x);
a(@""("");a(x);a(@"", "");a(y);a(@"")"");
}
}
")));
        }
        public void TemplateAttributeAdded()
        {
            var c = CompilationHelper.Compile("", new TextTemplatePreprocessor());

            Assert.Empty(c.GetDiagnostics());
            Assert.Contains(c.SyntaxTrees, s => s.FilePath.Contains("TemplateAttribute.cs"));
        }
        public async Task NestedTypes()
        {
            var c = CompilationHelper.Compile(@"using System;
using System.Linq;

namespace X.Y
{
    namespace Z
    {
        interface A
        {
            public class B
            {
                public record C<T>
                {
                    public struct D<U, V>
                    {
                        [Template]
                        public partial void M1(int n, DateTime d, List<(int x, int y)> list);

                        [Template]
                        internal partial void M2(System.Text.StringBuilder builder);
                    }
                }
            }
        }
    }
}");

            var root = await c.SyntaxTrees.First().GetRootAsync();

            var m = root.DescendantNodes(n => n is not MethodDeclarationSyntax).OfType <MethodDeclarationSyntax>();
            var t = (TypeDeclarationSyntax)m.First().Parent;

            var result = SyntaxNodeFormatter.Format(t, m, _ => (new(""), "any name"));

            Assert.Equal(@"#pragma warning disable 8019
using System;
using System.Linq;
namespace X.Y {
namespace Z {
partial interface A {
partial class B {
partial record C<T> {
partial struct D<U, V> {
public partial void M1(int n, DateTime d, List<(int x, int y)> list)
{

}
internal partial void M2(System.Text.StringBuilder builder)
{

}
}}}}}}
", result);
        }
        public void NoPartial()
        {
            var c = CompilationHelper.Compile("class A { [TextTemplate.Template(\"\")] private void M() { } }", new TextTemplatePreprocessor());

            Assert.Empty(c.GetDiagnostics());
            Assert.Equal(2, c.SyntaxTrees.Count());

            c = CompilationHelper.Compile("abstract class A { [TextTemplate.Template(\"\")] protected abstract void M(); }", new TextTemplatePreprocessor());
            Assert.Empty(c.GetDiagnostics());
            Assert.Equal(2, c.SyntaxTrees.Count());
        }
        public async Task SimpleTemplate()
        {
            var c = CompilationHelper.Compile(@"using System.Text;

class A
{
    public static partial void M(StringBuilder builder, int x, int y);
}");

            var root = await c.SyntaxTrees.First().GetRootAsync();

            var m = root.DescendantNodes(n => n is not MethodDeclarationSyntax).OfType <MethodDeclarationSyntax>();
            var t = (TypeDeclarationSyntax)m.First().Parent;

            var result = SyntaxNodeFormatter.Format(t, m, _ => (new(@"new[] {$<
for (var i = x; i < y; ++i)
{
$>
    $i,
$<
}
$>};"), "builder.Append"));

            Assert.Equal(@"#pragma warning disable 8019
using System.Text;
partial class A {
public static partial void M(StringBuilder builder, int x, int y)
{
builder.Append(@""new[] {"");
for (var i = x; i < y; ++i)
{
builder.Append(@""
    "");builder.Append(i);builder.Append(@"",
"");
}
builder.Append(@""};"");
}
}
", result);
        }
        public void NoTemplateArguments()
        {
            var c = CompilationHelper.Compile("class A { [TextTemplate.Template] private partial void M(); }", new TextTemplatePreprocessor());

            Assert.Equal(2, c.SyntaxTrees.Count());
        }