mirror of
https://github.com/github/codeql.git
synced 2026-04-23 07:45:17 +02:00
Merge pull request #7577 from michaelnebel/csharp/line-pragma
C#: Make support for Line span pragma
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
description: Remove support for line span pragma.
|
||||
compatibility: backwards
|
||||
directive_line_offset.rel: delete
|
||||
directive_line_span.rel: delete
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add support for line span pragma.
|
||||
compatibility: backwards
|
||||
12
csharp/ql/test/library-tests/csharp10/LinePragmas.cs
Normal file
12
csharp/ql/test/library-tests/csharp10/LinePragmas.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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 |
|
||||
13
csharp/ql/test/library-tests/csharp10/linePragmas.ql
Normal file
13
csharp/ql/test/library-tests/csharp10/linePragmas.ql
Normal 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()
|
||||
}
|
||||
Reference in New Issue
Block a user