2015-04-18 66 views
3

我試圖將標記和瑣事映射到使用Roslyn的行號。將標記和瑣事映射到行號

下面是@Kevin Pilch-Bisson幫助下的最新嘗試。

public class CSharpSlocAnalyser : ISlocAnalyser 
{ 
    public long GetSlocFor(IEnumerable<FileInfo> files, SlocOptions options) 
    { 
     var tree = CSharpSyntaxTree.ParseText(
@"using /* Blah */ 
    System; 
// Blah 
public class MyClass 
{ 
    public void MyMethod() 
    { 
     var blah = ""abc""; 
    } 
}"); 

     var root = tree.GetRoot(); 
     var walker = new CustomWalker(); 
     walker.Visit(root); 
     var lineMap = walker.LineMap; 

     return 1; 
    } 

    public class CustomWalker : CSharpSyntaxWalker 
    { 
     public Dictionary<int, List<object>> LineMap { get; } 

     public CustomWalker() : base(SyntaxWalkerDepth.StructuredTrivia) 
     { 
      LineMap = new Dictionary<int, List<object>>(); 
     } 

     public override void VisitToken(SyntaxToken token) 
     { 
      var parent = token.Parent; 
      while (parent.GetText().Length < token.Span.Start) 
      { 
       parent = parent.Parent; 
      } 

      var text = parent.GetText(); 
      var line = text.Lines.GetLineFromPosition(token.Span.Start).LineNumber; 

      if (!LineMap.ContainsKey(line)) 
      { 
       LineMap.Add(line, new List<object>()); 
      } 

      LineMap[line].Add(token); 

      base.VisitToken(token); 
     } 

     public override void VisitTrivia(SyntaxTrivia trivia) 
     { 
      var parent = trivia.Token.Parent; 
      while (parent.GetText().Length < trivia.Span.Start) 
      { 
       parent = parent.Parent; 
      } 

      var text = parent.GetText(); 
      var line = text.Lines.GetLineFromPosition(trivia.Span.Start).LineNumber; 

      if (!LineMap.ContainsKey(line)) 
      { 
       LineMap.Add(line, new List<object>()); 
      } 

      LineMap[line].Add(trivia); 

      base.VisitTrivia(trivia); 
     } 
    } 
} 

然而,這將產生以下地圖:

Line 0 
    UsingKeyword - 'using' 
    WhitespaceTrivia - ' ' 
    MultiLineCommentTrivia - '/* Blah */' 
    EndOfLineTrivia - ' 
' 
Line 1 
    IdentifierToken - 'System' 
    WhitespaceTrivia - ' ' 
    SemicolonToken - ';' 
    EndOfLineTrivia - ' 
' 
Line 2 
    SingleLineCommentTrivia - '// Blah' 
Line 3 
    PublicKeyword - 'public' 
    EndOfLineTrivia - ' 
' 
    WhitespaceTrivia - ' ' 
    ClassKeyword - 'class' 
    WhitespaceTrivia - ' ' 
    IdentifierToken - 'MyClass' 
    EndOfLineTrivia - ' 
' 
    WhitespaceTrivia - ' ' 
Line 4 
    OpenBraceToken - '{' 
    EndOfLineTrivia - ' 
' 
    PublicKeyword - 'public' 
Line 5 
    WhitespaceTrivia - ' ' 
    VoidKeyword - 'void' 
    WhitespaceTrivia - ' ' 
    IdentifierToken - 'MyMethod' 
    OpenParenToken - '(' 
    CloseParenToken - ')' 
    EndOfLineTrivia - ' 
' 
    WhitespaceTrivia - ' ' 
Line 6 
    OpenBraceToken - '{' 
    EndOfLineTrivia - ' 
' 
    WhitespaceTrivia - '  ' 
Line 7 
    IdentifierToken - 'var' 
    WhitespaceTrivia - ' ' 
    IdentifierToken - 'blah' 
    WhitespaceTrivia - ' ' 
    EqualsToken - '=' 
    WhitespaceTrivia - ' ' 
    StringLiteralToken - '"abc"' 
    SemicolonToken - ';' 
    EndOfLineTrivia - ' 
' 
Line 8 
    CloseBraceToken - '}' 
    WhitespaceTrivia - ' ' 
    EndOfLineTrivia - ' 
' 
Line 9 
    CloseBraceToken - '}' 
    EndOfFileToken - '' 

一切看起來都不錯,直到2號線,它不包含和線路瑣事的結束,3號線包含行瑣事的2月底,一切似乎從那裏離開鐵路。

我在做什麼錯?我只想將令牌和瑣事映射到原始源代碼行號。

回答

2

SourceText已經追蹤以Lines屬性結尾的行。您可以使用類似的代碼在GetLineAndOffset

+0

我不知道如何使用它來獲取一個行號的令牌。你能給一個樣品嗎? – ConditionRacer

+1

我更新了我的示例,請檢查一下嗎? – ConditionRacer

+0

是的,這是正確的。如果您查看'SyntaxNode.GetText'上的doc註釋,它會說:「將此節點的全文作爲* new *'SourceText'實例獲取。」 (原文如此)(強調我的)。這意味着它創建一個新的'SourceText',其中'SyntaxNode'是樹的根,這不是你想要的。 –

1

這工作:

public class CSharpSlocAnalyser : ISlocAnalyser 
{ 
    public long GetSlocFor(IEnumerable<FileInfo> files, SlocOptions options) 
    { 
     var tree = CSharpSyntaxTree.ParseText(
@"using /* Blah */ 
    System; 
// Blah 
public class MyClass 
{ 
    public void MyMethod() 
    { 
     var blah = ""abc""; 
    } 
}"); 

     var root = tree.GetRoot(); 
     var walker = new CustomWalker(); 
     walker.Visit(root); 
     var lineMap = walker.LineMap; 

     return 1; 
    } 

    public class CustomWalker : CSharpSyntaxWalker 
    { 
     public Dictionary<int, List<object>> LineMap { get; } 

     public CustomWalker() : base(SyntaxWalkerDepth.StructuredTrivia) 
     { 
      LineMap = new Dictionary<int, List<object>>(); 
     } 

     public override void VisitToken(SyntaxToken token) 
     { 
      var parent = token.SyntaxTree.GetRoot(); 

      AddLine(token, token.Span.Start, parent); 

      base.VisitToken(token); 
     } 

     public override void VisitTrivia(SyntaxTrivia trivia) 
     { 
      var parent = trivia.SyntaxTree.GetRoot(); 

      AddLine(trivia, trivia.Span.Start, parent); 

      base.VisitTrivia(trivia); 
     } 

     private void AddLine(object tokenOrTrivia, int position, SyntaxNode parent) 
     { 
      var text = parent.GetText(); 
      var line = text.Lines.GetLineFromPosition(position).LineNumber; 

      if (!LineMap.ContainsKey(line)) 
      { 
       LineMap.Add(line, new List<object>()); 
      } 

      LineMap[line].Add(tokenOrTrivia); 
     } 
    } 
} 

基本上,我只需要使用根syntaxtree爲GetLineFromPosition電話。

這產生了以下的地圖,這是正確的:

Line 0 
    UsingKeyword - 'using' 
    WhitespaceTrivia - ' ' 
    MultiLineCommentTrivia - '/* Blah */' 
    EndOfLineTrivia - ' 
' 
Line 1 
    IdentifierToken - 'System' 
    WhitespaceTrivia - ' ' 
    SemicolonToken - ';' 
    EndOfLineTrivia - ' 
' 
Line 2 
    SingleLineCommentTrivia - '// Blah' 
    EndOfLineTrivia - ' 
' 
Line 3 
    PublicKeyword - 'public' 
    WhitespaceTrivia - ' ' 
    ClassKeyword - 'class' 
    WhitespaceTrivia - ' ' 
    IdentifierToken - 'MyClass' 
    EndOfLineTrivia - ' 
' 
Line 4 
    OpenBraceToken - '{' 
    EndOfLineTrivia - ' 
' 
Line 5 
    PublicKeyword - 'public' 
    WhitespaceTrivia - ' ' 
    WhitespaceTrivia - ' ' 
    VoidKeyword - 'void' 
    WhitespaceTrivia - ' ' 
    IdentifierToken - 'MyMethod' 
    OpenParenToken - '(' 
    CloseParenToken - ')' 
    EndOfLineTrivia - ' 
' 
Line 6 
    OpenBraceToken - '{' 
    WhitespaceTrivia - ' ' 
    EndOfLineTrivia - ' 
' 
Line 7 
    IdentifierToken - 'var' 
    WhitespaceTrivia - '  ' 
    WhitespaceTrivia - ' ' 
    IdentifierToken - 'blah' 
    WhitespaceTrivia - ' ' 
    EqualsToken - '=' 
    WhitespaceTrivia - ' ' 
    StringLiteralToken - '"abc"' 
    SemicolonToken - ';' 
    EndOfLineTrivia - ' 
' 
Line 8 
    CloseBraceToken - '}' 
    WhitespaceTrivia - ' ' 
    EndOfLineTrivia - ' 
' 
Line 9 
    CloseBraceToken - '}' 
    EndOfFileToken - ''