İlkay İlknur

just a developer...

Roslyn - CSharpSyntaxWalker İle Syntax Tree Üzerinde Gezinme

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Bir önceki roslyn makalemizde syntax tree yapısından ve syntax tree içerisinde bulunan yapılardan bahsetmiştik. Ayrıca syntax tree içerisinde istediğimiz yapıdaki elementleri bulmak için LINQ kullanmıştık. Bu yazıda ise syntax tree içerisinde gezinmenin farklı bir yolunu inceleyeceğiz. İlk olarak projemize yine Microsoft.CodeAnalysis nuget paketini ekliyoruz.

Install-Package Microsoft.CodeAnalysis 

Genelde syntax treeler ile çalışırken amacımız belirli bir tipte olan elementleri bulup bunlar üzerinde işlemler yapmak oluyor. Örneğin, tüm class tanımlamalarını bulup kontrol etmek veya değişken tanımlamalarını bulup kontrol etmek gibi... Bu nedenle aslında çoğunlukla ilk yaptığımız şey syntax tree içerisinde bulmayı amaçladığımız tanımlamalara gitmek. SyntaxWalker yapısı da otomatik olarak syntax tree üzerinde kolayca gezinmemizi ve istediğimiz tanımlamalara hızlıca ulaşmamızı sağlayan bir yapı. C# syntax tree'leri için bunun özelleşmiş hali de CSharpSyntaxWalker tipi. CSharpSyntaxWalker tipinin yapısına bakarsak bu tip abstract bir tip. Bu nedenle kendi SyntaxWalker tipimizi yazıp bu tipten türeteceğiz.

public class MethodWalker : CSharpSyntaxWalker
{

}

Diyelim ki çalıştığınız şirkette kullandığınız bir kodlama standardı var ve bu standarda göre yazdığınız metotların isimleri büyük harfle başlamalı. Bu nedenle syntax walker ile syntax tree içerisinde gezip metot tanımlamalarını bulup bu metotların isimlerini kontrol etmeliyiz.

Yukarıda gördüğünüz üzere CSharpSyntaxWalker içerisinde override edilebilecek çok sayıda metot var. Bu metotları override ettiğinizde syntax tree içerisinde metodun isminde yazan elementlere denk gelindiğinde override ettiğiniz metot çağırılıyor. Böylece sizde istediğiniz işlemleri burada yapabiliyorsunuz. En basitinden eğer tüm nodeları veya tokenları gezmek isterseniz Visit ve VisitToken metotlarını override edebilirsiniz. Böylece hızlı bir şekilde tree üzerinde istediğiniz elemanlara erişebilirsiniz.

public class MethodWalker : CSharpSyntaxWalker
{
    public override void VisitToken(SyntaxToken token)
    {
        base.VisitToken(token);
    }

    public override void Visit(SyntaxNode node)
    {
        base.Visit(node);
    }
}

Ancak daha spesifik tanımlamalara erişmekse amacınız daha özelleşmiş metotlar işinizi daha da kolaylaştırabilir. Bizim örneğinizde aslında biz sadece metot tanımlamalarına odaklanmak istiyoruz. Bu nedenle metot tanımlamalarına erişmek bizim için yeterli. Bu nedenle doğrudan VisitMethodDeclaration metodunu override ederek ilerliyoruz.

public class MethodWalker : CSharpSyntaxWalker
{
    public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
    {
        base.VisitMethodDeclaration(node);
    }
}

Şimdi sıra geldi ilgili kontrolü yapma aşamasına. VisitMethodDeclaration metodunu override ettiğimizde bize artık MethodDeclarationSyntax node'u parametre olarak geliyor. Artık yapmamız gereken metot adının ilk harfini kontrol edip bir eğer illegal bir kullanım varsa ismini collection içerisine eklemek.

public class MethodWalker : CSharpSyntaxWalker
{
    public List<string> illegalMethodNames = new List<string>();
    public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
    {
        if (char.IsLower(node.Identifier.ValueText, 0))
        {
            illegalMethodNames.Add(node.Identifier.ValueText);
        }
    }
}

Gördüğünüz gibi bu kadar basit. Şimdi sıra geldi bu yazdığımız syntax walker aracılığıyla kod üzerinde gezinmeye.

class Program
{
    static void Main(string[] args)
    {
        var tree = CSharpSyntaxTree.ParseText(@"class Foo
                {
                    void Bar()
                    {
                    }

                    void bar1()
                    {
                        //Illegal
                    }

                    void Bar2()
                    {
                    }

                    void m()
                    {
                        //Illegal
                    }

                    class InnerFoo
                    {
                        void innerM()
                        {
                            //Illegal
                        }
                    }
                }"
);

        MethodWalker methodWalker = new MethodWalker();
        methodWalker.Visit(tree.GetRoot());

        methodWalker.illegalMethodNames.ForEach(t => Console.WriteLine(t));
    }
}

Gördüğünüz gibi syntax tree yarattıktan sonra syntax walkerın visit metodunu syntax tree'nin rootunu göndererek çağırıyoruz ve ağaç üzerinde gezinmeye başlıyoruz. Uygulamayı çalıştırırsak çıktı olarak küçük harfle başlayan metotların isimlerinin ekrana yazıldığını görebiliriz.

Gördüğünüz üzere syntax tree üzerinde gezinmek roslyn API'ları sayesinde oldukça kolay. Siz de kod içerisinde belirli analizleri yapmak için hızlı bir şekilde ve oldukça az kod yazıp ilgili kontrolleri yapabilirsiniz. Peki analizleri yaptık ve hataları kısımları bulduk. Bunları nasıl temizleyeceğiz ? Örneğin küçük harfle başlayan metotların isimlerini otomatik olarak değiştirsek nasıl olur ? Bu da bir sonraki roslyn makalesinin konusu olacak :)

Bir sonraki makalede görüşmek üzere...



Yorum Gönder