2015-07-31 16 views
6

Yöntemlerden öznitelikleri kaldırmak için kullanıyorum bir CSharpSyntaxRewriter yazdım, ancak bir yöntemi tüm öznitelikleri kaldırırken öznitelik (önceki yönteme kadar) önce bir şey tutmak için mücadele ediyorum.Üyelik özelliği nasıl kaldırılır, boş bir satır mı bırakılır?

Bu, birden fazla özniteliği olan yöntemlerde mükemmel çalışır, ancak yalnızca bir tanesini değil.

İşte minimal üreme var:

void Main() 
{ 
    var code = @"namespace P 
{ 
    class Program 
    { 
     public void NoAttributes() { } 
     //??? 
     [TestCategory(""Atomic"")] 
     public void OneAtt1() { } 

     [TestCategory(""Atomic"")] 
     public void OneAtt2() { } 

     [TestMethod, TestCategory(""Atomic"")] 
     public void TwoAtts() { } 
    } 
}"; 
    var tree = CSharpSyntaxTree.ParseText(code); 
    var rewriter = new AttributeRemoverRewriter(); 

    var rewrittenRoot = rewriter.Visit(tree.GetRoot()); 

    Console.WriteLine(rewrittenRoot.GetText().ToString()); 
} 

public class AttributeRemoverRewriter : CSharpSyntaxRewriter 
{ 
    public override SyntaxNode VisitAttributeList(AttributeListSyntax attributeList) 
    { 
     var nodesToRemove = 
      attributeList 
      .Attributes 
      .Where(att => (att.Name as IdentifierNameSyntax).Identifier.Text.StartsWith("TestCategory")) 
      .ToArray(); 

     if (nodesToRemove.Length == attributeList.Attributes.Count) 
     { 
      //Remove the entire attribute 
      return 
       attributeList 
       .RemoveNode(attributeList, SyntaxRemoveOptions.KeepNoTrivia); 
     } 
     else 
     { 
      //Remove just the matching ones recursively 
      foreach (var node in nodesToRemove) 
       return 
        VisitAttributeList(attributeList.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia)); 
     } 

     return 
      base.VisitAttributeList(attributeList); 
    } 
} 

Tam sürüm üzerinde burada benim gist (herkes diğer sorunları işaret önce).

Beklenen çıktısı:

namespace P 
{ 
    class Program 
    { 
     public void NoAttributes() { } 
     //??? 

     public void OneAtt1() { } 

     public void OneAtt2() { } 

     [TestMethod] 
     public void TwoAtts() { } 
    } 
} 

Gerçek çıktısı:

namespace P 
{ 
    class Program 
    { 
    public void NoAttributes() { } 
    public void OneAtt1() { } 
    public void OneAtt2() { } 

    [TestMethod] 
    public void TwoAtts() { } 
    } 
} 

herhangi bir fikir Ben boşluk tutmak için yapmanız gerekenler üzerinde (veya hatta yorum !!)?

Trivia'un her kombinasyonu ile uğraştım. SyntaxRemoveOptions'un değiştirilmesi, Roslyn kod tabanının içinde NullReferenceException5 s'nin bulunmasıyla sonuçlanır ve *Trivia uzantı yöntemlerinin kullanılması, artık kaldırılmayan özelliklerle sonuçlanır - sadece beyaz boşluk.

+0

Bu istisnalar bana hata gibi görünüyor. Bunları yerel olarak yeniden ürettim ve 'SyntaxRemoveOptions' değiştirilmesinin istisnalara neden olması gerektiğini düşünmüyorum. Bir sorun yaratmalısınız: https://github.com/dotnet/roslyn/issues – JoshVarty

cevap

1

Yorumlarda dediğim gibi, Roslyn'deki bir hata bana benziyor. Bunu bildirebilir ve isterseniz aşağıdaki geçici çözümü kullanabilirsiniz.

Sadece öznitelik düzeyinde değil, yöntem düzeyinde yeniden yazmayı denedim. (Özelliklerde benzer bir yaklaşımı kullanabilirsiniz)

public class AttributeRemoverRewriter : CSharpSyntaxRewriter 
{ 
    public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) 
    { 
     var newAttributes = new SyntaxList<AttributeListSyntax>(); 

     foreach (var attributeList in node.AttributeLists) 
     { 
      var nodesToRemove = 
      attributeList 
      .Attributes 
      .Where(att => (att.Name as IdentifierNameSyntax).Identifier.Text.StartsWith("TestCategory")) 
      .ToArray(); 

      if (nodesToRemove.Length == attributeList.Attributes.Count) 
      { 
       //Do not add the attribute to the list. It's being removed completely. 
      } 
      else 
      { 
       //We want to remove only some of the attributes 
       var newAttribute = (AttributeListSyntax)VisitAttributeList(attributeList.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia)); 
       newAttributes = newAttributes.Add(newAttribute); 
      } 
     } 

     //Get the leading trivia (the newlines and comments) 
     var leadTriv = node.GetLeadingTrivia(); 
     node = node.WithAttributeLists(newAttributes); 

     //Append the leading trivia to the method 
     node = node.WithLeadingTrivia(leadTriv); 
     return node; 
    } 
} 
İşte aldığım çıktı. Yorumları kaldırmak isterseniz leadTriv numaralı telefonu filtreleyebilirsiniz. Bu belli ... sapık durumları kapsamadığını

My output

Not:

[TestCategory(""Atomic"")] 
#if Debug 
#endif 
/*Trivia in unfortunate places*/ 
[TestCategory("test")] 
public void OneAtt2() { } 

Sen nitelikler arası önemsiz şeyler kaybedersiniz. Trivia, yeniden yazmayı oluştururken en doğru şeylerden biri.

+0

Teşekkürler Josh, belirsiz bilgiler hakkında endişelenmiyorum, ama sanırım takım için github üzerine bir konu kaydedeceğim. – DaveShaw

+0

Sadece birinin [[''] içinde 2 öznitelik ilan ettiğinde ve bir satır sonuyla ayrılmasının içerdiği bir boşluk olduğunda, bu soruyu yayınladıktan sonra bulduğum başka bir sorunu fark ettim. – DaveShaw

İlgili konular