Skip to content

Commit 547f492

Browse files
authored
Merge pull request github#7577 from michaelnebel/csharp/line-pragma
C#: Make support for Line span pragma
2 parents 70f4efb + d7cd1cf commit 547f492

File tree

19 files changed

+10390
-1592
lines changed

19 files changed

+10390
-1592
lines changed

csharp/downgrades/ff083666c7f75e0d039182cb6344a7be1a2f0421/old.dbscheme

Lines changed: 2098 additions & 0 deletions
Large diffs are not rendered by default.

csharp/downgrades/ff083666c7f75e0d039182cb6344a7be1a2f0421/semmlecode.csharp.dbscheme

Lines changed: 2088 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
description: Remove support for line span pragma.
2+
compatibility: backwards
3+
directive_line_offset.rel: delete
4+
directive_line_span.rel: delete
5+

csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,28 @@
55

66
namespace Semmle.Extraction.CSharp.Entities
77
{
8-
internal class LineDirective : PreprocessorDirective<LineDirectiveTriviaSyntax>
8+
internal class LineDirective : LineOrSpanDirective<LineDirectiveTriviaSyntax>
99
{
1010
private LineDirective(Context cx, LineDirectiveTriviaSyntax trivia)
11-
: base(cx, trivia)
11+
: base(cx, trivia, trivia.Line.Kind() switch
12+
{
13+
SyntaxKind.DefaultKeyword => LineDirectiveKind.Default,
14+
SyntaxKind.HiddenKeyword => LineDirectiveKind.Hidden,
15+
SyntaxKind.NumericLiteralToken => LineDirectiveKind.Numeric,
16+
_ => throw new InternalError(trivia, "Unhandled line token kind")
17+
})
1218
{
1319
}
1420

1521
protected override void PopulatePreprocessor(TextWriter trapFile)
1622
{
17-
var type = Symbol.Line.Kind() switch
18-
{
19-
SyntaxKind.DefaultKeyword => 0,
20-
SyntaxKind.HiddenKeyword => 1,
21-
SyntaxKind.NumericLiteralToken => 2,
22-
_ => throw new InternalError(Symbol, "Unhandled line token kind")
23-
};
24-
25-
trapFile.directive_lines(this, type);
26-
2723
if (Symbol.Line.IsKind(SyntaxKind.NumericLiteralToken))
2824
{
2925
var value = (int)Symbol.Line.Value!;
3026
trapFile.directive_line_value(this, value);
31-
32-
if (!string.IsNullOrWhiteSpace(Symbol.File.ValueText))
33-
{
34-
var file = File.Create(Context, Symbol.File.ValueText);
35-
trapFile.directive_line_file(this, file);
36-
}
3727
}
28+
29+
base.PopulatePreprocessor(trapFile);
3830
}
3931

4032
public static LineDirective Create(Context cx, LineDirectiveTriviaSyntax line) =>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using System.IO;
5+
6+
namespace Semmle.Extraction.CSharp.Entities
7+
{
8+
internal enum LineDirectiveKind
9+
{
10+
Default = 0,
11+
Hidden = 1,
12+
Numeric = 2,
13+
Span = 3
14+
}
15+
16+
internal abstract class LineOrSpanDirective<T> : PreprocessorDirective<T> where T : LineOrSpanDirectiveTriviaSyntax
17+
{
18+
private readonly LineDirectiveKind kind;
19+
20+
protected LineOrSpanDirective(Context cx, T trivia, LineDirectiveKind k)
21+
: base(cx, trivia)
22+
{
23+
kind = k;
24+
}
25+
26+
protected override void PopulatePreprocessor(TextWriter trapFile)
27+
{
28+
trapFile.directive_lines(this, kind);
29+
30+
if (!string.IsNullOrWhiteSpace(Symbol.File.ValueText))
31+
{
32+
var file = File.Create(Context, Symbol.File.ValueText);
33+
trapFile.directive_line_file(this, file);
34+
}
35+
}
36+
}
37+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using System.IO;
5+
6+
namespace Semmle.Extraction.CSharp.Entities
7+
{
8+
internal class LineSpanDirective : LineOrSpanDirective<LineSpanDirectiveTriviaSyntax>
9+
{
10+
private LineSpanDirective(Context cx, LineSpanDirectiveTriviaSyntax trivia)
11+
: base(cx, trivia, LineDirectiveKind.Span) { }
12+
13+
public static LineSpanDirective Create(Context cx, LineSpanDirectiveTriviaSyntax line) =>
14+
LineSpanDirectiveFactory.Instance.CreateEntity(cx, line, line);
15+
16+
protected override void PopulatePreprocessor(TextWriter trapFile)
17+
{
18+
var startLine = (int)Symbol.Start.Line.Value!;
19+
var startColumn = (int)Symbol.Start.Character.Value!;
20+
var endLine = (int)Symbol.End.Line.Value!;
21+
var endColumn = (int)Symbol.End.Character.Value!;
22+
trapFile.directive_line_span(this, startLine, startColumn, endLine, endColumn);
23+
24+
if (Symbol.CharacterOffset.Value is int offset)
25+
{
26+
trapFile.directive_line_offset(this, offset);
27+
}
28+
29+
base.PopulatePreprocessor(trapFile);
30+
}
31+
32+
private class LineSpanDirectiveFactory : CachedEntityFactory<LineSpanDirectiveTriviaSyntax, LineSpanDirective>
33+
{
34+
public static LineSpanDirectiveFactory Instance { get; } = new LineSpanDirectiveFactory();
35+
36+
public override LineSpanDirective Create(Context cx, LineSpanDirectiveTriviaSyntax init) => new(cx, init);
37+
}
38+
}
39+
}

csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,50 +17,35 @@ internal class DirectiveVisitor : CSharpSyntaxWalker
1717
/// </summary>
1818
public IEnumerable<IEntity> BranchesTaken => branchesTaken;
1919

20-
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia)
21-
{
20+
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia) =>
2221
this.cx = cx;
23-
}
2422

25-
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node)
26-
{
23+
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node) =>
2724
Entities.PragmaWarningDirective.Create(cx, node);
28-
}
2925

30-
public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node)
31-
{
26+
public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node) =>
3227
Entities.PragmaChecksumDirective.Create(cx, node);
33-
}
3428

35-
public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node)
36-
{
29+
public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node) =>
3730
Entities.DefineDirective.Create(cx, node);
38-
}
3931

40-
public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node)
41-
{
32+
public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node) =>
4233
Entities.UndefineDirective.Create(cx, node);
43-
}
4434

45-
public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node)
46-
{
35+
public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node) =>
4736
Entities.WarningDirective.Create(cx, node);
48-
}
4937

50-
public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node)
51-
{
38+
public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node) =>
5239
Entities.ErrorDirective.Create(cx, node);
53-
}
5440

55-
public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node)
56-
{
41+
public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) =>
5742
Entities.NullableDirective.Create(cx, node);
58-
}
5943

60-
public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node)
61-
{
44+
public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node) =>
6245
Entities.LineDirective.Create(cx, node);
63-
}
46+
47+
public override void VisitLineSpanDirectiveTrivia(LineSpanDirectiveTriviaSyntax node) =>
48+
Entities.LineSpanDirective.Create(cx, node);
6449

6550
private readonly Stack<Entities.RegionDirective> regionStarts = new Stack<Entities.RegionDirective>();
6651

csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,15 +413,21 @@ internal static void directive_errors(this TextWriter trapFile, ErrorDirective d
413413
internal static void directive_nullables(this TextWriter trapFile, NullableDirective directive, int setting, int target) =>
414414
trapFile.WriteTuple("directive_nullables", directive, setting, target);
415415

416-
internal static void directive_lines(this TextWriter trapFile, LineDirective directive, int kind) =>
417-
trapFile.WriteTuple("directive_lines", directive, kind);
416+
internal static void directive_lines<T>(this TextWriter trapFile, LineOrSpanDirective<T> directive, LineDirectiveKind kind) where T : LineOrSpanDirectiveTriviaSyntax =>
417+
trapFile.WriteTuple("directive_lines", directive, (int)kind);
418418

419419
internal static void directive_line_value(this TextWriter trapFile, LineDirective directive, int line) =>
420420
trapFile.WriteTuple("directive_line_value", directive, line);
421421

422-
internal static void directive_line_file(this TextWriter trapFile, LineDirective directive, Extraction.Entities.File file) =>
422+
internal static void directive_line_file<T>(this TextWriter trapFile, LineOrSpanDirective<T> directive, Extraction.Entities.File file) where T : LineOrSpanDirectiveTriviaSyntax =>
423423
trapFile.WriteTuple("directive_line_file", directive, file);
424424

425+
internal static void directive_line_offset(this TextWriter trapFile, LineSpanDirective directive, int offset) =>
426+
trapFile.WriteTuple("directive_line_offset", directive, offset);
427+
428+
internal static void directive_line_span(this TextWriter trapFile, LineSpanDirective directive, int startLine, int startColumn, int endLine, int endColumn) =>
429+
trapFile.WriteTuple("directive_line_span", directive, startLine, startColumn, endLine, endColumn);
430+
425431
internal static void directive_regions(this TextWriter trapFile, RegionDirective directive, string name) =>
426432
trapFile.WriteTuple("directive_regions", directive, name);
427433

csharp/ql/lib/semmle/code/csharp/Preprocessor.qll

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,42 @@ class HiddenLineDirective extends LineDirective {
208208
override string getAPrimaryQlClass() { result = "HiddenLineDirective" }
209209
}
210210

211+
private class NumericOrSpanLineDirective extends LineDirective {
212+
NumericOrSpanLineDirective() { directive_lines(this, [2, 3]) }
213+
214+
/** Gets the referenced file of this directive. */
215+
File getReferencedFile() { directive_line_file(this, result) }
216+
}
217+
211218
/**
212-
* A numeric `#line` directive, such as `#line 200 file`
219+
* A numeric `#line` directive, such as `#line 200 file`.
213220
*/
214-
class NumericLineDirective extends LineDirective {
221+
class NumericLineDirective extends NumericOrSpanLineDirective {
215222
NumericLineDirective() { directive_lines(this, 2) }
216223

217224
/** Gets the line number of this directive. */
218225
int getLine() { directive_line_value(this, result) }
219226

220-
/** Gets the referenced file of this directive. */
221-
File getReferencedFile() { directive_line_file(this, result) }
222-
223227
override string getAPrimaryQlClass() { result = "NumericLineDirective" }
224228
}
225229

230+
/**
231+
* A line span `#line` directive, such as `#line (1, 1) - (3, 10) 5 file`.
232+
*/
233+
class SpanLineDirective extends NumericOrSpanLineDirective {
234+
SpanLineDirective() { directive_lines(this, 3) }
235+
236+
/** Gets the offset of this directive. */
237+
int getOffset() { directive_line_offset(this, result) }
238+
239+
/** Holds if the specified start and end positions match this SpanLineDirective. */
240+
predicate span(int startLine, int startColumn, int endLine, int endColumn) {
241+
directive_line_span(this, startLine, startColumn, endLine, endColumn)
242+
}
243+
244+
override string getAPrimaryQlClass() { result = "SpanLineDirective" }
245+
}
246+
226247
/**
227248
* A `#region` directive.
228249
*/

csharp/ql/lib/semmlecode.csharp.dbscheme

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,16 +385,26 @@ directive_endregions(
385385

386386
directive_lines(
387387
unique int id: @directive_line,
388-
int kind: int ref); /* 0: default, 1: hidden, 2: numeric */
388+
int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
389389

390390
directive_line_value(
391391
unique int id: @directive_line ref,
392392
int line: int ref);
393393

394394
directive_line_file(
395395
unique int id: @directive_line ref,
396-
int file: @file ref
397-
)
396+
int file: @file ref);
397+
398+
directive_line_offset(
399+
unique int id: @directive_line ref,
400+
int offset: int ref);
401+
402+
directive_line_span(
403+
unique int id: @directive_line ref,
404+
int startLine: int ref,
405+
int startColumn: int ref,
406+
int endLine: int ref,
407+
int endColumn: int ref);
398408

399409
directive_nullables(
400410
unique int id: @directive_nullable,

0 commit comments

Comments
 (0)