将标记和琐事映射到行号 [英] Map tokens and trivia to line numbers
问题描述
我正在尝试使用 Roslyn 将标记和琐事映射到行号.
I'm trying to map tokens and trivia to line numbers using Roslyn.
这是我在下方@Kevin Pilch-Bisson 的帮助下的最新尝试.
Here's my latest attempt with help from @Kevin Pilch-Bisson below.
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);
}
}
}
然而,这会产生以下地图:
However this produces the following map:
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 个行尾琐事,一切似乎都从那里脱离了轨道.
Everything looks good until Line 2, which does not contain and end of line trivia, Line 3 contains 2 end of line trivia's, and everything seems to go off the rails from there.
我做错了什么?我只想将标记和琐事映射到它们的原始源代码行号.
What am I doing wrong? I just want to map tokens and trivia to their original source line numbers.
推荐答案
SourceText
已经跟踪以 Lines
属性结尾的行.您可以使用类似于 GetLineAndOffset
The SourceText
already tracks the line ending in the Lines
property. You can use something like the code in GetLineAndOffset
这篇关于将标记和琐事映射到行号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!