Merge pull request #7577 from michaelnebel/csharp/line-pragma

C#: Make support for Line span pragma
This commit is contained in:
Michael Nebel
2022-01-20 09:51:57 +01:00
committed by GitHub
19 changed files with 10406 additions and 1608 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
description: Remove support for line span pragma.
compatibility: backwards
directive_line_offset.rel: delete
directive_line_span.rel: delete

View File

@@ -5,36 +5,28 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class LineDirective : PreprocessorDirective<LineDirectiveTriviaSyntax>
internal class LineDirective : LineOrSpanDirective<LineDirectiveTriviaSyntax>
{
private LineDirective(Context cx, LineDirectiveTriviaSyntax trivia)
: base(cx, trivia)
: base(cx, trivia, trivia.Line.Kind() switch
{
SyntaxKind.DefaultKeyword => LineDirectiveKind.Default,
SyntaxKind.HiddenKeyword => LineDirectiveKind.Hidden,
SyntaxKind.NumericLiteralToken => LineDirectiveKind.Numeric,
_ => throw new InternalError(trivia, "Unhandled line token kind")
})
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
var type = Symbol.Line.Kind() switch
{
SyntaxKind.DefaultKeyword => 0,
SyntaxKind.HiddenKeyword => 1,
SyntaxKind.NumericLiteralToken => 2,
_ => throw new InternalError(Symbol, "Unhandled line token kind")
};
trapFile.directive_lines(this, type);
if (Symbol.Line.IsKind(SyntaxKind.NumericLiteralToken))
{
var value = (int)Symbol.Line.Value!;
trapFile.directive_line_value(this, value);
if (!string.IsNullOrWhiteSpace(Symbol.File.ValueText))
{
var file = File.Create(Context, Symbol.File.ValueText);
trapFile.directive_line_file(this, file);
}
}
base.PopulatePreprocessor(trapFile);
}
public static LineDirective Create(Context cx, LineDirectiveTriviaSyntax line) =>

View File

@@ -0,0 +1,37 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal enum LineDirectiveKind
{
Default = 0,
Hidden = 1,
Numeric = 2,
Span = 3
}
internal abstract class LineOrSpanDirective<T> : PreprocessorDirective<T> where T : LineOrSpanDirectiveTriviaSyntax
{
private readonly LineDirectiveKind kind;
protected LineOrSpanDirective(Context cx, T trivia, LineDirectiveKind k)
: base(cx, trivia)
{
kind = k;
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_lines(this, kind);
if (!string.IsNullOrWhiteSpace(Symbol.File.ValueText))
{
var file = File.Create(Context, Symbol.File.ValueText);
trapFile.directive_line_file(this, file);
}
}
}
}

View File

@@ -0,0 +1,39 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class LineSpanDirective : LineOrSpanDirective<LineSpanDirectiveTriviaSyntax>
{
private LineSpanDirective(Context cx, LineSpanDirectiveTriviaSyntax trivia)
: base(cx, trivia, LineDirectiveKind.Span) { }
public static LineSpanDirective Create(Context cx, LineSpanDirectiveTriviaSyntax line) =>
LineSpanDirectiveFactory.Instance.CreateEntity(cx, line, line);
protected override void PopulatePreprocessor(TextWriter trapFile)
{
var startLine = (int)Symbol.Start.Line.Value!;
var startColumn = (int)Symbol.Start.Character.Value!;
var endLine = (int)Symbol.End.Line.Value!;
var endColumn = (int)Symbol.End.Character.Value!;
trapFile.directive_line_span(this, startLine, startColumn, endLine, endColumn);
if (Symbol.CharacterOffset.Value is int offset)
{
trapFile.directive_line_offset(this, offset);
}
base.PopulatePreprocessor(trapFile);
}
private class LineSpanDirectiveFactory : CachedEntityFactory<LineSpanDirectiveTriviaSyntax, LineSpanDirective>
{
public static LineSpanDirectiveFactory Instance { get; } = new LineSpanDirectiveFactory();
public override LineSpanDirective Create(Context cx, LineSpanDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

View File

@@ -17,50 +17,35 @@ namespace Semmle.Extraction.CSharp.Populators
/// </summary>
public IEnumerable<IEntity> BranchesTaken => branchesTaken;
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia)
{
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia) =>
this.cx = cx;
}
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node)
{
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node) =>
Entities.PragmaWarningDirective.Create(cx, node);
}
public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node)
{
public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node) =>
Entities.PragmaChecksumDirective.Create(cx, node);
}
public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node)
{
public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node) =>
Entities.DefineDirective.Create(cx, node);
}
public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node)
{
public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node) =>
Entities.UndefineDirective.Create(cx, node);
}
public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node)
{
public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node) =>
Entities.WarningDirective.Create(cx, node);
}
public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node)
{
public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node) =>
Entities.ErrorDirective.Create(cx, node);
}
public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node)
{
public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) =>
Entities.NullableDirective.Create(cx, node);
}
public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node)
{
public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node) =>
Entities.LineDirective.Create(cx, node);
}
public override void VisitLineSpanDirectiveTrivia(LineSpanDirectiveTriviaSyntax node) =>
Entities.LineSpanDirective.Create(cx, node);
private readonly Stack<Entities.RegionDirective> regionStarts = new Stack<Entities.RegionDirective>();

View File

@@ -413,15 +413,21 @@ namespace Semmle.Extraction.CSharp
internal static void directive_nullables(this TextWriter trapFile, NullableDirective directive, int setting, int target) =>
trapFile.WriteTuple("directive_nullables", directive, setting, target);
internal static void directive_lines(this TextWriter trapFile, LineDirective directive, int kind) =>
trapFile.WriteTuple("directive_lines", directive, kind);
internal static void directive_lines<T>(this TextWriter trapFile, LineOrSpanDirective<T> directive, LineDirectiveKind kind) where T : LineOrSpanDirectiveTriviaSyntax =>
trapFile.WriteTuple("directive_lines", directive, (int)kind);
internal static void directive_line_value(this TextWriter trapFile, LineDirective directive, int line) =>
trapFile.WriteTuple("directive_line_value", directive, line);
internal static void directive_line_file(this TextWriter trapFile, LineDirective directive, Extraction.Entities.File file) =>
internal static void directive_line_file<T>(this TextWriter trapFile, LineOrSpanDirective<T> directive, Extraction.Entities.File file) where T : LineOrSpanDirectiveTriviaSyntax =>
trapFile.WriteTuple("directive_line_file", directive, file);
internal static void directive_line_offset(this TextWriter trapFile, LineSpanDirective directive, int offset) =>
trapFile.WriteTuple("directive_line_offset", directive, offset);
internal static void directive_line_span(this TextWriter trapFile, LineSpanDirective directive, int startLine, int startColumn, int endLine, int endColumn) =>
trapFile.WriteTuple("directive_line_span", directive, startLine, startColumn, endLine, endColumn);
internal static void directive_regions(this TextWriter trapFile, RegionDirective directive, string name) =>
trapFile.WriteTuple("directive_regions", directive, name);

View File

@@ -208,21 +208,42 @@ class HiddenLineDirective extends LineDirective {
override string getAPrimaryQlClass() { result = "HiddenLineDirective" }
}
private class NumericOrSpanLineDirective extends LineDirective {
NumericOrSpanLineDirective() { directive_lines(this, [2, 3]) }
/** Gets the referenced file of this directive. */
File getReferencedFile() { directive_line_file(this, result) }
}
/**
* A numeric `#line` directive, such as `#line 200 file`
* A numeric `#line` directive, such as `#line 200 file`.
*/
class NumericLineDirective extends LineDirective {
class NumericLineDirective extends NumericOrSpanLineDirective {
NumericLineDirective() { directive_lines(this, 2) }
/** Gets the line number of this directive. */
int getLine() { directive_line_value(this, result) }
/** Gets the referenced file of this directive. */
File getReferencedFile() { directive_line_file(this, result) }
override string getAPrimaryQlClass() { result = "NumericLineDirective" }
}
/**
* A line span `#line` directive, such as `#line (1, 1) - (3, 10) 5 file`.
*/
class SpanLineDirective extends NumericOrSpanLineDirective {
SpanLineDirective() { directive_lines(this, 3) }
/** Gets the offset of this directive. */
int getOffset() { directive_line_offset(this, result) }
/** Holds if the specified start and end positions match this SpanLineDirective. */
predicate span(int startLine, int startColumn, int endLine, int endColumn) {
directive_line_span(this, startLine, startColumn, endLine, endColumn)
}
override string getAPrimaryQlClass() { result = "SpanLineDirective" }
}
/**
* A `#region` directive.
*/

View File

@@ -385,7 +385,7 @@ directive_endregions(
directive_lines(
unique int id: @directive_line,
int kind: int ref); /* 0: default, 1: hidden, 2: numeric */
int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
directive_line_value(
unique int id: @directive_line ref,
@@ -393,8 +393,18 @@ directive_line_value(
directive_line_file(
unique int id: @directive_line ref,
int file: @file ref
)
int file: @file ref);
directive_line_offset(
unique int id: @directive_line ref,
int offset: int ref);
directive_line_span(
unique int id: @directive_line ref,
int startLine: int ref,
int startColumn: int ref,
int endLine: int ref,
int endColumn: int ref);
directive_nullables(
unique int id: @directive_nullable,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add support for line span pragma.
compatibility: backwards

View File

@@ -0,0 +1,12 @@
using System;
public class MyLineDirective
{
public static void M1()
{
#line (1, 1) - (1, 30) 5 "LinePragmasRef1.cs"
int i = 0;
#line (2, 1) - (5, 32) "LinePragmasRef2.cs"
int j = 0;
}
}

View File

@@ -0,0 +1,5 @@
linespan_directives
| LinePragmas.cs:7:1:7:45 | #line ... | 1 | 1 | 1 | 30 | LinePragmasRef1.cs:0:0:0:0 | LinePragmasRef1.cs |
| LinePragmas.cs:9:1:9:43 | #line ... | 2 | 1 | 5 | 32 | LinePragmasRef2.cs:0:0:0:0 | LinePragmasRef2.cs |
linespan_offset
| LinePragmas.cs:7:1:7:45 | #line ... | 5 | LinePragmasRef1.cs:0:0:0:0 | LinePragmasRef1.cs |

View File

@@ -0,0 +1,13 @@
import csharp
query predicate linespan_directives(
SpanLineDirective directive, int startLine, int startColumn, int endLine, int endColumn, File file
) {
file = directive.getReferencedFile() and
directive.span(startLine, startColumn, endLine, endColumn)
}
query predicate linespan_offset(SpanLineDirective directive, int offset, File file) {
file = directive.getReferencedFile() and
offset = directive.getOffset()
}