Skip to content

Commit d39a929

Browse files
authored
Render source snippet on location (#291)
This is something I implemented in my project's test implementation and found very helpful on large source generator samples - rendering the actual source snippet as an output comment, with squiggly lines underlining the problematic section, similar to what you get when compiling in the console. Unfortunately, only one test in this repo uses locations from actual source trees, so it might be harder to see the benefits, but even this modified example should give an idea of what it looks like.
1 parent 5ee50d8 commit d39a929

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
: (1,0)-(1,14)
1+
/*
2+
class Foo {
3+
void Bar() { }
4+
^^^^^^^^^^^^^^
5+
}
6+
*/
7+
theFile.cs: (1,0)-(1,14)

src/Tests/SyntaxLocationTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ void Bar() { }
1111
""";
1212

1313
var source = SourceText.From(sourceText);
14-
var syntaxTree = SyntaxFactory.ParseSyntaxTree(source);
14+
var syntaxTree = SyntaxFactory.ParseSyntaxTree(source, path: "theFile.cs");
1515

1616
var methodDeclarationSyntax = syntaxTree
1717
.GetRoot()
Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,37 @@
11
class LocationConverter :
22
WriteOnlyJsonConverter<Location>
33
{
4-
public override void Write(VerifyJsonWriter writer, Location value) =>
5-
writer.Serialize(value.GetMappedLineSpan());
6-
}
4+
const int contextLines = 1;
5+
6+
public override void Write(VerifyJsonWriter writer, Location value)
7+
{
8+
var lineSpan = value.GetMappedLineSpan();
9+
10+
// Pretty-print the error with the source code snippet.
11+
if (value.SourceTree is { } source)
12+
{
13+
var comment = new StringBuilder().AppendLine();
14+
var lines = source.GetText().Lines;
15+
var startLine = Math.Max(lineSpan.StartLinePosition.Line - contextLines, 0);
16+
var endLine = Math.Min(lineSpan.EndLinePosition.Line + contextLines, lines.Count - 1);
17+
for (var lineIdx = startLine; lineIdx <= endLine; lineIdx++)
18+
{
19+
var line = lines[lineIdx];
20+
// print the source line
21+
comment.AppendLine(line.ToString());
22+
// print squiggly line highlighting the location
23+
if (line.Span.Intersection(value.SourceSpan) is { } intersection)
24+
{
25+
comment
26+
.Append(' ', intersection.Start - line.Start)
27+
.Append('^', intersection.Length)
28+
.AppendLine();
29+
}
30+
}
31+
writer.WriteComment(comment.ToString());
32+
writer.WriteWhitespace("\n");
33+
}
34+
35+
writer.Serialize(lineSpan);
36+
}
37+
}

0 commit comments

Comments
 (0)