将标记和琐事映射到行号
Map tokens and trivia to line numbers
我正在尝试使用 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 个行尾琐事,从那里开始一切似乎都偏离了 rails。
我做错了什么?我只想将标记和琐事映射到它们的原始源代码行号。
SourceText
已经跟踪了以 Lines
属性 结尾的行。您可以使用类似 GetLineAndOffset
中的代码
这有效:
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);
}
}
}
基本上我只需要为 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 - ''
我正在尝试使用 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 个行尾琐事,从那里开始一切似乎都偏离了 rails。
我做错了什么?我只想将标记和琐事映射到它们的原始源代码行号。
SourceText
已经跟踪了以 Lines
属性 结尾的行。您可以使用类似 GetLineAndOffset
这有效:
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);
}
}
}
基本上我只需要为 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 - ''