将令牌和琐事映射到行号

我正在尝试使用Roslyn将令牌和琐事映射到行号。

以下是@Kevin Pilch-Bisson帮助下的最新尝试。

public class CSharpSlocAnalyser : ISlocAnalyser { public long GetSlocFor(IEnumerable 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> LineMap { get; } public CustomWalker() : base(SyntaxWalkerDepth.StructuredTrivia) { LineMap = new Dictionary<int, List>(); } 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()); } 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()); } 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行尾行琐事,一切似乎从那里走出轨道。

我究竟做错了什么? 我只想将令牌和琐事映射到原始源代码行。

SourceText已经跟踪以Lines属性结尾的Lines 。 您可以使用GetLineAndOffset的代码

这工作:

 public class CSharpSlocAnalyser : ISlocAnalyser { public long GetSlocFor(IEnumerable 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> LineMap { get; } public CustomWalker() : base(SyntaxWalkerDepth.StructuredTrivia) { LineMap = new Dictionary>(); } 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()); } 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 - ''