From af6e1bda4c5bc02e1833289d69e219f8c26349a3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 20 Mar 2025 15:18:19 +0100 Subject: [PATCH 1/9] C#: Extract alignment and format clauses of string interpolation expressions. --- .../SymbolExtensions.cs | 9 ++++ .../Entities/Expressions/Binary.cs | 2 +- .../Entities/Expressions/ImplicitToString.cs | 7 +-- .../Expressions/InterpolatedString.cs | 11 +--- .../Expressions/InterpolatedStringInsert.cs | 41 +++++++++++++++ .../Kinds/ExprKind.cs | 1 + .../internal/TaintTrackingPrivate.qll | 3 ++ .../ql/lib/semmle/code/csharp/exprs/Expr.qll | 51 ++++++++++++++++--- csharp/ql/lib/semmlecode.csharp.dbscheme | 1 + 9 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedStringInsert.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs index cb1f36f8a2de..72f78f160598 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs @@ -29,6 +29,15 @@ public AnnotatedTypeSymbol(ITypeSymbol? symbol, NullableAnnotation nullability) symbol is null ? (AnnotatedTypeSymbol?)null : new AnnotatedTypeSymbol(symbol, NullableAnnotation.None); } + internal static class AnnotatedTypeSymbolExtensions + { + /// + /// Returns true if the type is a string type. + /// + public static bool IsStringType(this AnnotatedTypeSymbol? type) => + type.HasValue && type.Value.Symbol?.SpecialType == SpecialType.System_String; + } + internal static class SymbolExtensions { /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs index eeb1b9ba63b2..d4cc5cc81d58 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs @@ -18,7 +18,7 @@ private Expression CreateChild(Context cx, ExpressionSyntax node, int child) { // If this is a "+" expression we might need to wrap the child expressions // in ToString calls - return Kind == ExprKind.ADD + return Kind == ExprKind.ADD && Type.IsStringType() ? ImplicitToString.Create(cx, node, this, child) : Create(cx, node, this, child); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs index 32c00f8a729e..bebc0c2c5d81 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs @@ -39,16 +39,13 @@ private ImplicitToString(ExpressionNodeInfo info, IMethodSymbol toString) : base Context.TrapWriter.Writer.expr_call(this, target); } - private static bool IsStringType(AnnotatedTypeSymbol? type) => - type.HasValue && type.Value.Symbol?.SpecialType == SpecialType.System_String; - /// /// Creates a new expression, adding a compiler generated `ToString` call if required. /// - public static Expression Create(Context cx, ExpressionSyntax node, Expression parent, int child) + public static Expression Create(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) { var info = new ExpressionNodeInfo(cx, node, parent, child); - return CreateFromNode(info.SetImplicitToString(IsStringType(parent.Type) && !IsStringType(info.Type))); + return CreateFromNode(info.SetImplicitToString(!info.Type.IsStringType())); } /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs index 6d17d1e7f176..5cd13dffe20b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs @@ -1,5 +1,4 @@ using System.IO; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; @@ -21,15 +20,7 @@ protected override void PopulateExpression(TextWriter trapFile) { case SyntaxKind.Interpolation: var interpolation = (InterpolationSyntax)c; - var exp = interpolation.Expression; - if (Context.GetTypeInfo(exp).Type is ITypeSymbol type && !type.ImplementsIFormattable()) - { - ImplicitToString.Create(Context, exp, this, child++); - } - else - { - Create(Context, exp, this, child++); - } + new InterpolatedStringInsert(Context, interpolation, this, child++); break; case SyntaxKind.InterpolatedStringText: // Create a string literal diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedStringInsert.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedStringInsert.cs new file mode 100644 index 000000000000..beac4bc64a64 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedStringInsert.cs @@ -0,0 +1,41 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities.Expressions +{ + internal class InterpolatedStringInsert : Expression + { + public InterpolatedStringInsert(Context cx, InterpolationSyntax syntax, Expression parent, int child) : + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), ExprKind.INTERPOLATED_STRING_INSERT, parent, child, isCompilerGenerated: false, null)) + { + var exp = syntax.Expression; + if (parent.Type.IsStringType() && + cx.GetTypeInfo(exp).Type is ITypeSymbol type && + !type.ImplementsIFormattable()) + { + ImplicitToString.Create(cx, exp, this, 0); + } + else + { + Create(cx, exp, this, 0); + } + + // Hardcode the child number of the optional alignment clause to 1 and format clause to 2. + // This simplifies the logic in QL. + if (syntax.AlignmentClause?.Value is ExpressionSyntax alignment) + { + Create(cx, alignment, this, 1); + } + + if (syntax.FormatClause is InterpolationFormatClauseSyntax format) + { + var f = format.FormatStringToken.ValueText; + var t = AnnotatedTypeSymbol.CreateNotAnnotated(cx.Compilation.GetSpecialType(SpecialType.System_String)); + new Expression(new ExpressionInfo(cx, t, cx.CreateLocation(format.GetLocation()), ExprKind.UTF16_STRING_LITERAL, this, 2, isCompilerGenerated: false, f)); + } + + } + } + +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs index 297acda9524c..46a694192842 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs @@ -132,6 +132,7 @@ public enum ExprKind UTF8_STRING_LITERAL = 135, COLLECTION = 136, SPREAD_ELEMENT = 137, + INTERPOLATED_STRING_INSERT = 138, DEFINE_SYMBOL = 999, } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 1a044a77777d..b7681994e2c3 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -66,6 +66,9 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon e1 = e2.(InterpolatedStringExpr).getAChild() and scope = e2 or + e1 = e2.(InterpolatedStringInsertExpr).getInsert() and + scope = e2 + or e2 = any(OperatorCall oc | oc.getTarget().(ConversionOperator).fromLibrary() and diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index 85676bbd2701..ada010652588 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -34,8 +34,9 @@ private import semmle.code.csharp.TypeRef * `as` expression (`AsExpr`), a cast (`CastExpr`), a `typeof` expression * (`TypeofExpr`), a `default` expression (`DefaultValueExpr`), an `await` * expression (`AwaitExpr`), a `nameof` expression (`NameOfExpr`), an - * interpolated string (`InterpolatedStringExpr`), a qualifiable expression - * (`QualifiableExpr`), or a literal (`Literal`). + * interpolated string (`InterpolatedStringExpr`), an interpolated string + * insert (`InterpolatedStringInsertExpr`), a qualifiable expression (`QualifiableExpr`), + * or a literal (`Literal`). */ class Expr extends ControlFlowElement, @expr { override Location getALocation() { expr_location(this, result) } @@ -917,6 +918,40 @@ class NameOfExpr extends Expr, @nameof_expr { override string getAPrimaryQlClass() { result = "NameOfExpr" } } +/** + * An interpolated string insert, for example `{pi, align:F3}` on line 3 in + * + * ```csharp + * void Pi() { + * float pi = 3.14159f; + * Console.WriteLine($"Hello Pi, {pi,6:F3}"); + * } + * ``` + */ +class InterpolatedStringInsertExpr extends Expr, @interpolated_string_insert_expr { + override string toString() { result = "{...}" } + + override string getAPrimaryQlClass() { result = "InterpolatedStringInsertExpr" } + + /** + * Gets the insert expression in this interpolated string insert. For + * example, the insert expression in `{pi, align:F3}` is `pi`. + */ + Expr getInsert() { result = this.getChild(0) } + + /** + * Gets the alignment expression in this interpolated string insert, if any. + * For example, the alignment expression in `{pi, align:F3}` is `align`. + */ + Expr getAlignment() { result = this.getChild(1) } + + /** + * Gets the format expression in this interpolated string insert, if any. + * For example, the format expression in `{pi, align:F3}` is `F3`. + */ + StringLiteral getFormat() { result = this.getChild(2) } +} + /** * An interpolated string, for example `$"Hello, {name}!"` on line 2 in * @@ -931,16 +966,20 @@ class InterpolatedStringExpr extends Expr, @interpolated_string_expr { override string getAPrimaryQlClass() { result = "InterpolatedStringExpr" } + /** + * Gets the interpolated string insert at index `i` in this interpolated string, if any. + * For example, the interpolated string insert at index `i = 1` is `{pi, align:F3}` + * in `$"Hello, {pi, align:F3}!"`. + */ + InterpolatedStringInsertExpr getInterpolatedInsert(int i) { result = this.getChild(i) } + /** * Gets the insert at index `i` in this interpolated string, if any. For * example, the insert at index `i = 1` is `name` in `$"Hello, {name}!"`. * Note that there is no insert at index `i = 0`, but instead a text * element (`getText(0)` gets the text). */ - Expr getInsert(int i) { - result = this.getChild(i) and - not result instanceof StringLiteral - } + Expr getInsert(int i) { result = this.getInterpolatedInsert(i).getInsert() } /** * Gets the text element at index `i` in this interpolated string, if any. diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index a2bda57dbc6e..66044cfa5bbf 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -1168,6 +1168,7 @@ case @expr.kind of /* C# 12.0 */ | 136 = @collection_expr | 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr /* Preprocessor */ | 999 = @define_symbol_expr ; From 2ca5ec00321f5cb2a17b1ffa1514c26dc917e65d Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 20 Mar 2025 15:43:03 +0100 Subject: [PATCH 2/9] C#: Add some string interpolation tests with alignment and formatting. --- .../StringInterpolation.cs | 17 +++++++++++++ .../library-tests/stringinterpolation/options | 2 ++ .../stringInterpolation.expected | 23 +++++++++++++++++ .../stringInterpolation.ql | 25 +++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 csharp/ql/test/library-tests/stringinterpolation/StringInterpolation.cs create mode 100644 csharp/ql/test/library-tests/stringinterpolation/options create mode 100644 csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.expected create mode 100644 csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql diff --git a/csharp/ql/test/library-tests/stringinterpolation/StringInterpolation.cs b/csharp/ql/test/library-tests/stringinterpolation/StringInterpolation.cs new file mode 100644 index 000000000000..d14c3d75e465 --- /dev/null +++ b/csharp/ql/test/library-tests/stringinterpolation/StringInterpolation.cs @@ -0,0 +1,17 @@ +using System; + +public class MyStringInterpolationClass +{ + + public void M() + { + float i = 3.14159f; + const int align = 5; + var x1 = $"Hello, Pi {i}"; + var x2 = $"Hello, Pi {i:F1}"; + var x3 = $"Hello, Pi {i,6}"; + var x4 = $"Hello, Pi {i,6:F3}"; + var x5 = $"Hello, Pi {i,align}"; + var x6 = $"Hello, Pi {i,align:F2}"; + } +} diff --git a/csharp/ql/test/library-tests/stringinterpolation/options b/csharp/ql/test/library-tests/stringinterpolation/options new file mode 100644 index 000000000000..77b22963f5c8 --- /dev/null +++ b/csharp/ql/test/library-tests/stringinterpolation/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.expected b/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.expected new file mode 100644 index 000000000000..9ce88ad83c31 --- /dev/null +++ b/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.expected @@ -0,0 +1,23 @@ +inserts +| StringInterpolation.cs:10:18:10:33 | $"..." | StringInterpolation.cs:10:31:10:31 | access to local variable i | +| StringInterpolation.cs:11:18:11:36 | $"..." | StringInterpolation.cs:11:31:11:31 | access to local variable i | +| StringInterpolation.cs:12:18:12:35 | $"..." | StringInterpolation.cs:12:31:12:31 | access to local variable i | +| StringInterpolation.cs:13:18:13:38 | $"..." | StringInterpolation.cs:13:31:13:31 | access to local variable i | +| StringInterpolation.cs:14:18:14:39 | $"..." | StringInterpolation.cs:14:31:14:31 | access to local variable i | +| StringInterpolation.cs:15:18:15:42 | $"..." | StringInterpolation.cs:15:31:15:31 | access to local variable i | +texts +| StringInterpolation.cs:10:18:10:33 | $"..." | StringInterpolation.cs:10:20:10:29 | "Hello, Pi " | +| StringInterpolation.cs:11:18:11:36 | $"..." | StringInterpolation.cs:11:20:11:29 | "Hello, Pi " | +| StringInterpolation.cs:12:18:12:35 | $"..." | StringInterpolation.cs:12:20:12:29 | "Hello, Pi " | +| StringInterpolation.cs:13:18:13:38 | $"..." | StringInterpolation.cs:13:20:13:29 | "Hello, Pi " | +| StringInterpolation.cs:14:18:14:39 | $"..." | StringInterpolation.cs:14:20:14:29 | "Hello, Pi " | +| StringInterpolation.cs:15:18:15:42 | $"..." | StringInterpolation.cs:15:20:15:29 | "Hello, Pi " | +interpolationInsertsWithAlign +| StringInterpolation.cs:12:18:12:35 | $"..." | StringInterpolation.cs:12:31:12:31 | access to local variable i | StringInterpolation.cs:12:33:12:33 | 6 | +| StringInterpolation.cs:13:18:13:38 | $"..." | StringInterpolation.cs:13:31:13:31 | access to local variable i | StringInterpolation.cs:13:33:13:33 | 6 | +| StringInterpolation.cs:14:18:14:39 | $"..." | StringInterpolation.cs:14:31:14:31 | access to local variable i | StringInterpolation.cs:14:33:14:37 | access to local variable align | +| StringInterpolation.cs:15:18:15:42 | $"..." | StringInterpolation.cs:15:31:15:31 | access to local variable i | StringInterpolation.cs:15:33:15:37 | access to local variable align | +interpolationInsertsWithFormat +| StringInterpolation.cs:11:18:11:36 | $"..." | StringInterpolation.cs:11:31:11:31 | access to local variable i | StringInterpolation.cs:11:32:11:34 | "F1" | +| StringInterpolation.cs:13:18:13:38 | $"..." | StringInterpolation.cs:13:31:13:31 | access to local variable i | StringInterpolation.cs:13:34:13:36 | "F3" | +| StringInterpolation.cs:15:18:15:42 | $"..." | StringInterpolation.cs:15:31:15:31 | access to local variable i | StringInterpolation.cs:15:38:15:40 | "F2" | diff --git a/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql b/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql new file mode 100644 index 000000000000..21b33b12b56d --- /dev/null +++ b/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql @@ -0,0 +1,25 @@ +import csharp + +query predicate inserts(InterpolatedStringExpr expr, Expr e) { + expr.getAnInsert() = e // and inSpecificSource(expr) +} + +query predicate texts(InterpolatedStringExpr expr, StringLiteral literal) { + expr.getAText() = literal // and inSpecificSource(expr) +} + +query predicate interpolationInsertsWithAlign(InterpolatedStringExpr expr, Expr insert, Expr align) { + exists(InterpolatedStringInsertExpr e | expr.getInterpolatedInsert(_) = e | + insert = e.getInsert() and + align = e.getAlignment() + ) +} + +query predicate interpolationInsertsWithFormat( + InterpolatedStringExpr expr, Expr insert, StringLiteral format +) { + exists(InterpolatedStringInsertExpr e | expr.getInterpolatedInsert(_) = e | + insert = e.getInsert() and + format = e.getFormat() + ) +} From a73a61b8fa3916211950688690003867ba85f5c4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 21 Mar 2025 12:35:49 +0100 Subject: [PATCH 3/9] C#: Add PrintAst test for string interpolation expressions. --- .../stringinterpolation/PrintAst.expected | 70 +++++++++++++++++++ .../stringinterpolation/PrintAst.qlref | 1 + 2 files changed, 71 insertions(+) create mode 100644 csharp/ql/test/library-tests/stringinterpolation/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/stringinterpolation/PrintAst.qlref diff --git a/csharp/ql/test/library-tests/stringinterpolation/PrintAst.expected b/csharp/ql/test/library-tests/stringinterpolation/PrintAst.expected new file mode 100644 index 000000000000..6529f9feed5c --- /dev/null +++ b/csharp/ql/test/library-tests/stringinterpolation/PrintAst.expected @@ -0,0 +1,70 @@ +StringInterpolation.cs: +# 3| [Class] MyStringInterpolationClass +# 6| 5: [Method] M +# 6| -1: [TypeMention] Void +# 7| 4: [BlockStmt] {...} +# 8| 0: [LocalVariableDeclStmt] ... ...; +# 8| 0: [LocalVariableDeclAndInitExpr] Single i = ... +# 8| -1: [TypeMention] float +# 8| 0: [LocalVariableAccess] access to local variable i +# 8| 1: [FloatLiteral] 3.14159 +# 9| 1: [LocalConstantDeclStmt] const ... ...; +# 9| 0: [LocalVariableDeclAndInitExpr] Int32 align = ... +# 9| -1: [TypeMention] int +# 9| 0: [LocalVariableAccess] access to local variable align +# 9| 1: [IntLiteral] 5 +# 10| 2: [LocalVariableDeclStmt] ... ...; +# 10| 0: [LocalVariableDeclAndInitExpr] String x1 = ... +# 10| -1: [TypeMention] string +# 10| 0: [LocalVariableAccess] access to local variable x1 +# 10| 1: [InterpolatedStringExpr] $"..." +# 10| 0: [StringLiteralUtf16] "Hello, Pi " +# 10| 1: [InterpolatedStringInsertExpr] {...} +# 10| 0: [LocalVariableAccess] access to local variable i +# 11| 3: [LocalVariableDeclStmt] ... ...; +# 11| 0: [LocalVariableDeclAndInitExpr] String x2 = ... +# 11| -1: [TypeMention] string +# 11| 0: [LocalVariableAccess] access to local variable x2 +# 11| 1: [InterpolatedStringExpr] $"..." +# 11| 0: [StringLiteralUtf16] "Hello, Pi " +# 11| 1: [InterpolatedStringInsertExpr] {...} +# 11| 0: [LocalVariableAccess] access to local variable i +# 11| 2: [StringLiteralUtf16] "F1" +# 12| 4: [LocalVariableDeclStmt] ... ...; +# 12| 0: [LocalVariableDeclAndInitExpr] String x3 = ... +# 12| -1: [TypeMention] string +# 12| 0: [LocalVariableAccess] access to local variable x3 +# 12| 1: [InterpolatedStringExpr] $"..." +# 12| 0: [StringLiteralUtf16] "Hello, Pi " +# 12| 1: [InterpolatedStringInsertExpr] {...} +# 12| 0: [LocalVariableAccess] access to local variable i +# 12| 1: [IntLiteral] 6 +# 13| 5: [LocalVariableDeclStmt] ... ...; +# 13| 0: [LocalVariableDeclAndInitExpr] String x4 = ... +# 13| -1: [TypeMention] string +# 13| 0: [LocalVariableAccess] access to local variable x4 +# 13| 1: [InterpolatedStringExpr] $"..." +# 13| 0: [StringLiteralUtf16] "Hello, Pi " +# 13| 1: [InterpolatedStringInsertExpr] {...} +# 13| 0: [LocalVariableAccess] access to local variable i +# 13| 1: [IntLiteral] 6 +# 13| 2: [StringLiteralUtf16] "F3" +# 14| 6: [LocalVariableDeclStmt] ... ...; +# 14| 0: [LocalVariableDeclAndInitExpr] String x5 = ... +# 14| -1: [TypeMention] string +# 14| 0: [LocalVariableAccess] access to local variable x5 +# 14| 1: [InterpolatedStringExpr] $"..." +# 14| 0: [StringLiteralUtf16] "Hello, Pi " +# 14| 1: [InterpolatedStringInsertExpr] {...} +# 14| 0: [LocalVariableAccess] access to local variable i +# 14| 1: [LocalVariableAccess] access to local variable align +# 15| 7: [LocalVariableDeclStmt] ... ...; +# 15| 0: [LocalVariableDeclAndInitExpr] String x6 = ... +# 15| -1: [TypeMention] string +# 15| 0: [LocalVariableAccess] access to local variable x6 +# 15| 1: [InterpolatedStringExpr] $"..." +# 15| 0: [StringLiteralUtf16] "Hello, Pi " +# 15| 1: [InterpolatedStringInsertExpr] {...} +# 15| 0: [LocalVariableAccess] access to local variable i +# 15| 1: [LocalVariableAccess] access to local variable align +# 15| 2: [StringLiteralUtf16] "F2" diff --git a/csharp/ql/test/library-tests/stringinterpolation/PrintAst.qlref b/csharp/ql/test/library-tests/stringinterpolation/PrintAst.qlref new file mode 100644 index 000000000000..f867dd01f9f8 --- /dev/null +++ b/csharp/ql/test/library-tests/stringinterpolation/PrintAst.qlref @@ -0,0 +1 @@ +shared/PrintAst.ql \ No newline at end of file From 5ae7e5ddb3890de6369a6be488d45fcee416d819 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 21 Mar 2025 12:44:46 +0100 Subject: [PATCH 4/9] C#: Update other test expected output files. --- .../controlflow/graph/BasicBlock.expected | 18 +++---- .../controlflow/graph/Dominance.expected | 54 ++++++++++++------- .../graph/EnclosingCallable.expected | 9 ++++ .../controlflow/graph/EntryElement.expected | 9 ++++ .../controlflow/graph/ExitElement.expected | 9 ++++ .../controlflow/graph/NodeGraph.expected | 27 ++++++---- .../library-tests/csharp11/PrintAst.expected | 26 +++++---- .../csharp6/InterpolatedStringExpr.expected | 16 +++--- .../library-tests/csharp6/PrintAst.expected | 44 ++++++++------- .../library-tests/csharp7.3/PrintAst.expected | 3 +- .../library-tests/csharp7/IsFlow.expected | 12 +++-- .../csharp7/LocalTaintFlow.expected | 18 ++++--- .../library-tests/csharp7/PrintAst.expected | 18 ++++--- .../library-tests/csharp8/PrintAst.expected | 6 ++- .../library-tests/csharp9/PrintAst.expected | 5 +- .../implicittostring/PrintAst.expected | 10 ++-- .../dataflow/local/TaintTrackingStep.expected | 12 +++-- 17 files changed, 194 insertions(+), 102 deletions(-) diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index b3ea35fe7e4b..623b5404f781 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -377,8 +377,8 @@ | Conditions.cs:143:10:143:12 | exit M11 (normal) | Conditions.cs:143:10:143:12 | exit M11 | 2 | | Conditions.cs:145:21:145:23 | [b (line 143): true] "a" | Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | 5 | | Conditions.cs:145:27:145:29 | [b (line 143): false] "b" | Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | 5 | -| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:13:147:48 | call to method WriteLine | 5 | -| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:13:149:48 | call to method WriteLine | 5 | +| Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:13:147:48 | call to method WriteLine | 6 | +| Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:13:149:48 | call to method WriteLine | 6 | | ExitMethods.cs:6:7:6:17 | enter ExitMethods | ExitMethods.cs:6:7:6:17 | exit ExitMethods | 5 | | ExitMethods.cs:8:10:8:11 | enter M1 | ExitMethods.cs:8:10:8:11 | exit M1 | 8 | | ExitMethods.cs:14:10:14:11 | enter M2 | ExitMethods.cs:14:10:14:11 | exit M2 | 8 | @@ -859,11 +859,11 @@ | Patterns.cs:5:10:5:11 | enter M1 | Patterns.cs:8:18:8:23 | Int32 i1 | 8 | | Patterns.cs:8:13:8:23 | [false] ... is ... | Patterns.cs:8:13:8:23 | [false] ... is ... | 1 | | Patterns.cs:8:13:8:23 | [true] ... is ... | Patterns.cs:8:13:8:23 | [true] ... is ... | 1 | -| Patterns.cs:9:9:11:9 | {...} | Patterns.cs:10:13:10:42 | call to method WriteLine | 6 | +| Patterns.cs:9:9:11:9 | {...} | Patterns.cs:10:13:10:42 | call to method WriteLine | 7 | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:12:23:12:31 | String s1 | 3 | | Patterns.cs:12:18:12:31 | [false] ... is ... | Patterns.cs:12:18:12:31 | [false] ... is ... | 1 | | Patterns.cs:12:18:12:31 | [true] ... is ... | Patterns.cs:12:18:12:31 | [true] ... is ... | 1 | -| Patterns.cs:13:9:15:9 | {...} | Patterns.cs:14:13:14:45 | call to method WriteLine | 6 | +| Patterns.cs:13:9:15:9 | {...} | Patterns.cs:14:13:14:45 | call to method WriteLine | 7 | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:16:23:16:28 | Object v1 | 3 | | Patterns.cs:16:18:16:28 | [false] ... is ... | Patterns.cs:16:18:16:28 | [false] ... is ... | 1 | | Patterns.cs:16:18:16:28 | [true] ... is ... | Patterns.cs:16:18:16:28 | [true] ... is ... | 1 | @@ -872,11 +872,11 @@ | Patterns.cs:23:17:23:22 | break; | Patterns.cs:23:17:23:22 | break; | 1 | | Patterns.cs:24:13:24:36 | case ...: | Patterns.cs:24:18:24:23 | Int32 i2 | 2 | | Patterns.cs:24:30:24:31 | access to local variable i2 | Patterns.cs:24:30:24:35 | ... > ... | 3 | -| Patterns.cs:25:17:25:52 | ...; | Patterns.cs:26:17:26:22 | break; | 6 | +| Patterns.cs:25:17:25:52 | ...; | Patterns.cs:26:17:26:22 | break; | 7 | | Patterns.cs:27:13:27:24 | case ...: | Patterns.cs:27:18:27:23 | Int32 i3 | 2 | -| Patterns.cs:28:17:28:47 | ...; | Patterns.cs:29:17:29:22 | break; | 6 | +| Patterns.cs:28:17:28:47 | ...; | Patterns.cs:29:17:29:22 | break; | 7 | | Patterns.cs:30:13:30:27 | case ...: | Patterns.cs:30:18:30:26 | String s2 | 2 | -| Patterns.cs:31:17:31:50 | ...; | Patterns.cs:32:17:32:22 | break; | 6 | +| Patterns.cs:31:17:31:50 | ...; | Patterns.cs:32:17:32:22 | break; | 7 | | Patterns.cs:33:13:33:24 | case ...: | Patterns.cs:33:18:33:23 | Object v2 | 2 | | Patterns.cs:34:17:34:22 | break; | Patterns.cs:34:17:34:22 | break; | 1 | | Patterns.cs:35:13:35:20 | default: | Patterns.cs:37:17:37:22 | break; | 5 | @@ -1076,8 +1076,8 @@ | Switch.cs:156:36:156:38 | "a" | Switch.cs:156:28:156:38 | ... => ... | 2 | | Switch.cs:156:41:156:45 | false | Switch.cs:156:41:156:45 | false | 1 | | Switch.cs:156:50:156:52 | "b" | Switch.cs:156:41:156:52 | ... => ... | 2 | -| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:48 | call to method WriteLine | 5 | -| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:48 | call to method WriteLine | 5 | +| Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:48 | call to method WriteLine | 6 | +| Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:48 | call to method WriteLine | 6 | | TypeAccesses.cs:1:7:1:18 | enter TypeAccesses | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses | 5 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:18:7:22 | Int32 j | 13 | | TypeAccesses.cs:7:13:7:22 | [false] ... is ... | TypeAccesses.cs:7:13:7:22 | [false] ... is ... | 1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 7706539ad306..b2d700660689 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -1527,11 +1527,13 @@ dominance | Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:40:147:43 | "a = " | | Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:13:147:48 | call to method WriteLine | | Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:45:147:45 | access to local variable s | -| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:38:147:47 | $"..." | +| Conditions.cs:147:44:147:46 | {...} | Conditions.cs:147:38:147:47 | $"..." | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:44:147:46 | {...} | | Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:40:149:43 | "b = " | | Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:13:149:48 | call to method WriteLine | | Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:45:149:45 | access to local variable s | -| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:38:149:47 | $"..." | +| Conditions.cs:149:44:149:46 | {...} | Conditions.cs:149:38:149:47 | $"..." | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:44:149:46 | {...} | | ExitMethods.cs:6:7:6:17 | call to constructor Object | ExitMethods.cs:6:7:6:17 | {...} | | ExitMethods.cs:6:7:6:17 | enter ExitMethods | ExitMethods.cs:6:7:6:17 | call to constructor Object | | ExitMethods.cs:6:7:6:17 | exit ExitMethods (normal) | ExitMethods.cs:6:7:6:17 | exit ExitMethods | @@ -3147,7 +3149,8 @@ dominance | Patterns.cs:10:13:10:43 | ...; | Patterns.cs:10:33:10:36 | "int " | | Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:10:13:10:42 | call to method WriteLine | | Patterns.cs:10:33:10:36 | "int " | Patterns.cs:10:38:10:39 | access to local variable i1 | -| Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:31:10:41 | $"..." | +| Patterns.cs:10:37:10:40 | {...} | Patterns.cs:10:31:10:41 | $"..." | +| Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:37:10:40 | {...} | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:12:18:12:18 | access to local variable o | | Patterns.cs:12:18:12:18 | access to local variable o | Patterns.cs:12:23:12:31 | String s1 | | Patterns.cs:12:18:12:31 | [false] ... is ... | Patterns.cs:16:14:18:9 | if (...) ... | @@ -3158,7 +3161,8 @@ dominance | Patterns.cs:14:13:14:46 | ...; | Patterns.cs:14:33:14:39 | "string " | | Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:14:13:14:45 | call to method WriteLine | | Patterns.cs:14:33:14:39 | "string " | Patterns.cs:14:41:14:42 | access to local variable s1 | -| Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:31:14:44 | $"..." | +| Patterns.cs:14:40:14:43 | {...} | Patterns.cs:14:31:14:44 | $"..." | +| Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:40:14:43 | {...} | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:16:18:16:18 | access to local variable o | | Patterns.cs:16:18:16:18 | access to local variable o | Patterns.cs:16:23:16:28 | Object v1 | | Patterns.cs:16:18:16:28 | [true] ... is ... | Patterns.cs:17:9:18:9 | {...} | @@ -3179,7 +3183,8 @@ dominance | Patterns.cs:25:17:25:52 | ...; | Patterns.cs:25:37:25:45 | "positive " | | Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:25:17:25:51 | call to method WriteLine | | Patterns.cs:25:37:25:45 | "positive " | Patterns.cs:25:47:25:48 | access to local variable i2 | -| Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:35:25:50 | $"..." | +| Patterns.cs:25:46:25:49 | {...} | Patterns.cs:25:35:25:50 | $"..." | +| Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:46:25:49 | {...} | | Patterns.cs:27:13:27:24 | case ...: | Patterns.cs:27:18:27:23 | Int32 i3 | | Patterns.cs:27:18:27:23 | Int32 i3 | Patterns.cs:28:17:28:47 | ...; | | Patterns.cs:27:18:27:23 | Int32 i3 | Patterns.cs:30:13:30:27 | case ...: | @@ -3187,7 +3192,8 @@ dominance | Patterns.cs:28:17:28:47 | ...; | Patterns.cs:28:37:28:40 | "int " | | Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:28:17:28:46 | call to method WriteLine | | Patterns.cs:28:37:28:40 | "int " | Patterns.cs:28:42:28:43 | access to local variable i3 | -| Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:35:28:45 | $"..." | +| Patterns.cs:28:41:28:44 | {...} | Patterns.cs:28:35:28:45 | $"..." | +| Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:41:28:44 | {...} | | Patterns.cs:30:13:30:27 | case ...: | Patterns.cs:30:18:30:26 | String s2 | | Patterns.cs:30:18:30:26 | String s2 | Patterns.cs:31:17:31:50 | ...; | | Patterns.cs:30:18:30:26 | String s2 | Patterns.cs:33:13:33:24 | case ...: | @@ -3195,7 +3201,8 @@ dominance | Patterns.cs:31:17:31:50 | ...; | Patterns.cs:31:37:31:43 | "string " | | Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:31:17:31:49 | call to method WriteLine | | Patterns.cs:31:37:31:43 | "string " | Patterns.cs:31:45:31:46 | access to local variable s2 | -| Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:35:31:48 | $"..." | +| Patterns.cs:31:44:31:47 | {...} | Patterns.cs:31:35:31:48 | $"..." | +| Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:44:31:47 | {...} | | Patterns.cs:33:13:33:24 | case ...: | Patterns.cs:33:18:33:23 | Object v2 | | Patterns.cs:33:18:33:23 | Object v2 | Patterns.cs:34:17:34:22 | break; | | Patterns.cs:33:18:33:23 | Object v2 | Patterns.cs:35:13:35:20 | default: | @@ -3664,11 +3671,13 @@ dominance | Switch.cs:158:13:158:49 | ...; | Switch.cs:158:40:158:43 | "a = " | | Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:13:158:48 | call to method WriteLine | | Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:45:158:45 | access to local variable s | -| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:38:158:47 | $"..." | +| Switch.cs:158:44:158:46 | {...} | Switch.cs:158:38:158:47 | $"..." | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:44:158:46 | {...} | | Switch.cs:160:13:160:49 | ...; | Switch.cs:160:40:160:43 | "b = " | | Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:13:160:48 | call to method WriteLine | | Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:45:160:45 | access to local variable s | -| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:38:160:47 | $"..." | +| Switch.cs:160:44:160:46 | {...} | Switch.cs:160:38:160:47 | $"..." | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:44:160:46 | {...} | | TypeAccesses.cs:1:7:1:18 | call to constructor Object | TypeAccesses.cs:1:7:1:18 | {...} | | TypeAccesses.cs:1:7:1:18 | enter TypeAccesses | TypeAccesses.cs:1:7:1:18 | call to constructor Object | | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses (normal) | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses | @@ -5858,13 +5867,15 @@ postDominance | Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | Conditions.cs:146:9:149:49 | [b (line 143): true] if (...) ... | | Conditions.cs:147:13:147:48 | call to method WriteLine | Conditions.cs:147:38:147:47 | $"..." | | Conditions.cs:147:13:147:49 | ...; | Conditions.cs:146:13:146:13 | [b (line 143): true] access to parameter b | -| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:45:147:45 | access to local variable s | +| Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:44:147:46 | {...} | | Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:13:147:49 | ...; | +| Conditions.cs:147:44:147:46 | {...} | Conditions.cs:147:45:147:45 | access to local variable s | | Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:40:147:43 | "a = " | | Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:149:38:149:47 | $"..." | | Conditions.cs:149:13:149:49 | ...; | Conditions.cs:146:13:146:13 | [b (line 143): false] access to parameter b | -| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:45:149:45 | access to local variable s | +| Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:44:149:46 | {...} | | Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:13:149:49 | ...; | +| Conditions.cs:149:44:149:46 | {...} | Conditions.cs:149:45:149:45 | access to local variable s | | Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:40:149:43 | "b = " | | ExitMethods.cs:6:7:6:17 | call to constructor Object | ExitMethods.cs:6:7:6:17 | enter ExitMethods | | ExitMethods.cs:6:7:6:17 | exit ExitMethods | ExitMethods.cs:6:7:6:17 | exit ExitMethods (normal) | @@ -7341,8 +7352,9 @@ postDominance | Patterns.cs:9:9:11:9 | {...} | Patterns.cs:8:13:8:23 | [true] ... is ... | | Patterns.cs:10:13:10:42 | call to method WriteLine | Patterns.cs:10:31:10:41 | $"..." | | Patterns.cs:10:13:10:43 | ...; | Patterns.cs:9:9:11:9 | {...} | -| Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:10:38:10:39 | access to local variable i1 | +| Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:10:37:10:40 | {...} | | Patterns.cs:10:33:10:36 | "int " | Patterns.cs:10:13:10:43 | ...; | +| Patterns.cs:10:37:10:40 | {...} | Patterns.cs:10:38:10:39 | access to local variable i1 | | Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:33:10:36 | "int " | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:8:13:8:23 | [false] ... is ... | | Patterns.cs:12:18:12:18 | access to local variable o | Patterns.cs:12:14:18:9 | if (...) ... | @@ -7350,8 +7362,9 @@ postDominance | Patterns.cs:13:9:15:9 | {...} | Patterns.cs:12:18:12:31 | [true] ... is ... | | Patterns.cs:14:13:14:45 | call to method WriteLine | Patterns.cs:14:31:14:44 | $"..." | | Patterns.cs:14:13:14:46 | ...; | Patterns.cs:13:9:15:9 | {...} | -| Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:14:41:14:42 | access to local variable s1 | +| Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:14:40:14:43 | {...} | | Patterns.cs:14:33:14:39 | "string " | Patterns.cs:14:13:14:46 | ...; | +| Patterns.cs:14:40:14:43 | {...} | Patterns.cs:14:41:14:42 | access to local variable s1 | | Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:33:14:39 | "string " | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:12:18:12:31 | [false] ... is ... | | Patterns.cs:16:18:16:18 | access to local variable o | Patterns.cs:16:14:18:9 | if (...) ... | @@ -7368,20 +7381,23 @@ postDominance | Patterns.cs:24:30:24:35 | ... > ... | Patterns.cs:24:35:24:35 | 0 | | Patterns.cs:24:35:24:35 | 0 | Patterns.cs:24:30:24:31 | access to local variable i2 | | Patterns.cs:25:17:25:51 | call to method WriteLine | Patterns.cs:25:35:25:50 | $"..." | -| Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:25:47:25:48 | access to local variable i2 | +| Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:25:46:25:49 | {...} | | Patterns.cs:25:37:25:45 | "positive " | Patterns.cs:25:17:25:52 | ...; | +| Patterns.cs:25:46:25:49 | {...} | Patterns.cs:25:47:25:48 | access to local variable i2 | | Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:37:25:45 | "positive " | | Patterns.cs:26:17:26:22 | break; | Patterns.cs:25:17:25:51 | call to method WriteLine | | Patterns.cs:27:18:27:23 | Int32 i3 | Patterns.cs:27:13:27:24 | case ...: | | Patterns.cs:28:17:28:46 | call to method WriteLine | Patterns.cs:28:35:28:45 | $"..." | -| Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:28:42:28:43 | access to local variable i3 | +| Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:28:41:28:44 | {...} | | Patterns.cs:28:37:28:40 | "int " | Patterns.cs:28:17:28:47 | ...; | +| Patterns.cs:28:41:28:44 | {...} | Patterns.cs:28:42:28:43 | access to local variable i3 | | Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:37:28:40 | "int " | | Patterns.cs:29:17:29:22 | break; | Patterns.cs:28:17:28:46 | call to method WriteLine | | Patterns.cs:30:18:30:26 | String s2 | Patterns.cs:30:13:30:27 | case ...: | | Patterns.cs:31:17:31:49 | call to method WriteLine | Patterns.cs:31:35:31:48 | $"..." | -| Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:31:45:31:46 | access to local variable s2 | +| Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:31:44:31:47 | {...} | | Patterns.cs:31:37:31:43 | "string " | Patterns.cs:31:17:31:50 | ...; | +| Patterns.cs:31:44:31:47 | {...} | Patterns.cs:31:45:31:46 | access to local variable s2 | | Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:37:31:43 | "string " | | Patterns.cs:32:17:32:22 | break; | Patterns.cs:31:17:31:49 | call to method WriteLine | | Patterns.cs:33:18:33:23 | Object v2 | Patterns.cs:33:13:33:24 | case ...: | @@ -7829,12 +7845,14 @@ postDominance | Switch.cs:157:9:160:49 | if (...) ... | Switch.cs:156:13:156:54 | String s = ... | | Switch.cs:157:13:157:13 | access to parameter b | Switch.cs:157:9:160:49 | if (...) ... | | Switch.cs:158:13:158:48 | call to method WriteLine | Switch.cs:158:38:158:47 | $"..." | -| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:45:158:45 | access to local variable s | +| Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:44:158:46 | {...} | | Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:13:158:49 | ...; | +| Switch.cs:158:44:158:46 | {...} | Switch.cs:158:45:158:45 | access to local variable s | | Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:40:158:43 | "a = " | | Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:160:38:160:47 | $"..." | -| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:45:160:45 | access to local variable s | +| Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:44:160:46 | {...} | | Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:13:160:49 | ...; | +| Switch.cs:160:44:160:46 | {...} | Switch.cs:160:45:160:45 | access to local variable s | | Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:40:160:43 | "b = " | | TypeAccesses.cs:1:7:1:18 | call to constructor Object | TypeAccesses.cs:1:7:1:18 | enter TypeAccesses | | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses (normal) | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 4f208361ea1a..57e393adc39a 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -1642,11 +1642,13 @@ nodeEnclosing | Conditions.cs:147:13:147:49 | ...; | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:147:44:147:46 | {...} | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:149:13:149:49 | ...; | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:143:10:143:12 | M11 | +| Conditions.cs:149:44:149:46 | {...} | Conditions.cs:143:10:143:12 | M11 | | Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:143:10:143:12 | M11 | | ExitMethods.cs:6:7:6:17 | call to constructor Object | ExitMethods.cs:6:7:6:17 | ExitMethods | | ExitMethods.cs:6:7:6:17 | enter ExitMethods | ExitMethods.cs:6:7:6:17 | ExitMethods | @@ -3436,6 +3438,7 @@ nodeEnclosing | Patterns.cs:10:13:10:43 | ...; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:10:33:10:36 | "int " | Patterns.cs:5:10:5:11 | M1 | +| Patterns.cs:10:37:10:40 | {...} | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:12:18:12:18 | access to local variable o | Patterns.cs:5:10:5:11 | M1 | @@ -3447,6 +3450,7 @@ nodeEnclosing | Patterns.cs:14:13:14:46 | ...; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:14:33:14:39 | "string " | Patterns.cs:5:10:5:11 | M1 | +| Patterns.cs:14:40:14:43 | {...} | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:16:18:16:18 | access to local variable o | Patterns.cs:5:10:5:11 | M1 | @@ -3468,6 +3472,7 @@ nodeEnclosing | Patterns.cs:25:17:25:52 | ...; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:25:37:25:45 | "positive " | Patterns.cs:5:10:5:11 | M1 | +| Patterns.cs:25:46:25:49 | {...} | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:26:17:26:22 | break; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:27:13:27:24 | case ...: | Patterns.cs:5:10:5:11 | M1 | @@ -3476,6 +3481,7 @@ nodeEnclosing | Patterns.cs:28:17:28:47 | ...; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:28:37:28:40 | "int " | Patterns.cs:5:10:5:11 | M1 | +| Patterns.cs:28:41:28:44 | {...} | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:29:17:29:22 | break; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:30:13:30:27 | case ...: | Patterns.cs:5:10:5:11 | M1 | @@ -3484,6 +3490,7 @@ nodeEnclosing | Patterns.cs:31:17:31:50 | ...; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:31:37:31:43 | "string " | Patterns.cs:5:10:5:11 | M1 | +| Patterns.cs:31:44:31:47 | {...} | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:32:17:32:22 | break; | Patterns.cs:5:10:5:11 | M1 | | Patterns.cs:33:13:33:24 | case ...: | Patterns.cs:5:10:5:11 | M1 | @@ -4014,11 +4021,13 @@ nodeEnclosing | Switch.cs:158:13:158:49 | ...; | Switch.cs:154:10:154:12 | M15 | | Switch.cs:158:38:158:47 | $"..." | Switch.cs:154:10:154:12 | M15 | | Switch.cs:158:40:158:43 | "a = " | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:158:44:158:46 | {...} | Switch.cs:154:10:154:12 | M15 | | Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:154:10:154:12 | M15 | | Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:154:10:154:12 | M15 | | Switch.cs:160:13:160:49 | ...; | Switch.cs:154:10:154:12 | M15 | | Switch.cs:160:38:160:47 | $"..." | Switch.cs:154:10:154:12 | M15 | | Switch.cs:160:40:160:43 | "b = " | Switch.cs:154:10:154:12 | M15 | +| Switch.cs:160:44:160:46 | {...} | Switch.cs:154:10:154:12 | M15 | | Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:154:10:154:12 | M15 | | TypeAccesses.cs:1:7:1:18 | call to constructor Object | TypeAccesses.cs:1:7:1:18 | TypeAccesses | | TypeAccesses.cs:1:7:1:18 | enter TypeAccesses | TypeAccesses.cs:1:7:1:18 | TypeAccesses | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index fddab21f2b62..cc26ecf7c8ed 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1158,11 +1158,13 @@ | Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:13:147:49 | ...; | | Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:40:147:43 | "a = " | | Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:40:147:43 | "a = " | +| Conditions.cs:147:44:147:46 | {...} | Conditions.cs:147:45:147:45 | access to local variable s | | Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:45:147:45 | access to local variable s | | Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:149:40:149:43 | "b = " | | Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:13:149:49 | ...; | | Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:40:149:43 | "b = " | | Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:40:149:43 | "b = " | +| Conditions.cs:149:44:149:46 | {...} | Conditions.cs:149:45:149:45 | access to local variable s | | Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:45:149:45 | access to local variable s | | ExitMethods.cs:6:7:6:17 | call to constructor Object | ExitMethods.cs:6:7:6:17 | call to constructor Object | | ExitMethods.cs:6:7:6:17 | {...} | ExitMethods.cs:6:7:6:17 | {...} | @@ -2238,6 +2240,7 @@ | Patterns.cs:10:13:10:43 | ...; | Patterns.cs:10:13:10:43 | ...; | | Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:10:33:10:36 | "int " | | Patterns.cs:10:33:10:36 | "int " | Patterns.cs:10:33:10:36 | "int " | +| Patterns.cs:10:37:10:40 | {...} | Patterns.cs:10:38:10:39 | access to local variable i1 | | Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:38:10:39 | access to local variable i1 | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:12:14:18:9 | if (...) ... | | Patterns.cs:12:18:12:18 | access to local variable o | Patterns.cs:12:18:12:18 | access to local variable o | @@ -2248,6 +2251,7 @@ | Patterns.cs:14:13:14:46 | ...; | Patterns.cs:14:13:14:46 | ...; | | Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:14:33:14:39 | "string " | | Patterns.cs:14:33:14:39 | "string " | Patterns.cs:14:33:14:39 | "string " | +| Patterns.cs:14:40:14:43 | {...} | Patterns.cs:14:41:14:42 | access to local variable s1 | | Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:41:14:42 | access to local variable s1 | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:16:14:18:9 | if (...) ... | | Patterns.cs:16:18:16:18 | access to local variable o | Patterns.cs:16:18:16:18 | access to local variable o | @@ -2268,6 +2272,7 @@ | Patterns.cs:25:17:25:52 | ...; | Patterns.cs:25:17:25:52 | ...; | | Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:25:37:25:45 | "positive " | | Patterns.cs:25:37:25:45 | "positive " | Patterns.cs:25:37:25:45 | "positive " | +| Patterns.cs:25:46:25:49 | {...} | Patterns.cs:25:47:25:48 | access to local variable i2 | | Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:47:25:48 | access to local variable i2 | | Patterns.cs:26:17:26:22 | break; | Patterns.cs:26:17:26:22 | break; | | Patterns.cs:27:13:27:24 | case ...: | Patterns.cs:27:13:27:24 | case ...: | @@ -2276,6 +2281,7 @@ | Patterns.cs:28:17:28:47 | ...; | Patterns.cs:28:17:28:47 | ...; | | Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:28:37:28:40 | "int " | | Patterns.cs:28:37:28:40 | "int " | Patterns.cs:28:37:28:40 | "int " | +| Patterns.cs:28:41:28:44 | {...} | Patterns.cs:28:42:28:43 | access to local variable i3 | | Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:42:28:43 | access to local variable i3 | | Patterns.cs:29:17:29:22 | break; | Patterns.cs:29:17:29:22 | break; | | Patterns.cs:30:13:30:27 | case ...: | Patterns.cs:30:13:30:27 | case ...: | @@ -2284,6 +2290,7 @@ | Patterns.cs:31:17:31:50 | ...; | Patterns.cs:31:17:31:50 | ...; | | Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:31:37:31:43 | "string " | | Patterns.cs:31:37:31:43 | "string " | Patterns.cs:31:37:31:43 | "string " | +| Patterns.cs:31:44:31:47 | {...} | Patterns.cs:31:45:31:46 | access to local variable s2 | | Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:45:31:46 | access to local variable s2 | | Patterns.cs:32:17:32:22 | break; | Patterns.cs:32:17:32:22 | break; | | Patterns.cs:33:13:33:24 | case ...: | Patterns.cs:33:13:33:24 | case ...: | @@ -2696,11 +2703,13 @@ | Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:49 | ...; | | Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:40:158:43 | "a = " | | Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:40:158:43 | "a = " | +| Switch.cs:158:44:158:46 | {...} | Switch.cs:158:45:158:45 | access to local variable s | | Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:45:158:45 | access to local variable s | | Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:160:40:160:43 | "b = " | | Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:49 | ...; | | Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:40:160:43 | "b = " | | Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:40:160:43 | "b = " | +| Switch.cs:160:44:160:46 | {...} | Switch.cs:160:45:160:45 | access to local variable s | | Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:45:160:45 | access to local variable s | | TypeAccesses.cs:1:7:1:18 | call to constructor Object | TypeAccesses.cs:1:7:1:18 | call to constructor Object | | TypeAccesses.cs:1:7:1:18 | {...} | TypeAccesses.cs:1:7:1:18 | {...} | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index 81ee139f6a68..bc47b5b3fa26 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -1452,11 +1452,13 @@ | Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:13:147:48 | call to method WriteLine | normal | | Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:38:147:47 | $"..." | normal | | Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:40:147:43 | "a = " | normal | +| Conditions.cs:147:44:147:46 | {...} | Conditions.cs:147:44:147:46 | {...} | normal | | Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:45:147:45 | access to local variable s | normal | | Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:149:13:149:48 | call to method WriteLine | normal | | Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:13:149:48 | call to method WriteLine | normal | | Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:38:149:47 | $"..." | normal | | Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:40:149:43 | "b = " | normal | +| Conditions.cs:149:44:149:46 | {...} | Conditions.cs:149:44:149:46 | {...} | normal | | Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:45:149:45 | access to local variable s | normal | | ExitMethods.cs:6:7:6:17 | call to constructor Object | ExitMethods.cs:6:7:6:17 | call to constructor Object | normal | | ExitMethods.cs:6:7:6:17 | {...} | ExitMethods.cs:6:7:6:17 | {...} | normal | @@ -2911,6 +2913,7 @@ | Patterns.cs:10:13:10:43 | ...; | Patterns.cs:10:13:10:42 | call to method WriteLine | normal | | Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:10:31:10:41 | $"..." | normal | | Patterns.cs:10:33:10:36 | "int " | Patterns.cs:10:33:10:36 | "int " | normal | +| Patterns.cs:10:37:10:40 | {...} | Patterns.cs:10:37:10:40 | {...} | normal | | Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:38:10:39 | access to local variable i1 | normal | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:14:13:14:45 | call to method WriteLine | normal | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:16:18:16:28 | ... is ... | false | @@ -2925,6 +2928,7 @@ | Patterns.cs:14:13:14:46 | ...; | Patterns.cs:14:13:14:45 | call to method WriteLine | normal | | Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:14:31:14:44 | $"..." | normal | | Patterns.cs:14:33:14:39 | "string " | Patterns.cs:14:33:14:39 | "string " | normal | +| Patterns.cs:14:40:14:43 | {...} | Patterns.cs:14:40:14:43 | {...} | normal | | Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:41:14:42 | access to local variable s1 | normal | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:16:18:16:28 | ... is ... | false | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:17:9:18:9 | {...} | normal | @@ -2959,6 +2963,7 @@ | Patterns.cs:25:17:25:52 | ...; | Patterns.cs:25:17:25:51 | call to method WriteLine | normal | | Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:25:35:25:50 | $"..." | normal | | Patterns.cs:25:37:25:45 | "positive " | Patterns.cs:25:37:25:45 | "positive " | normal | +| Patterns.cs:25:46:25:49 | {...} | Patterns.cs:25:46:25:49 | {...} | normal | | Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:47:25:48 | access to local variable i2 | normal | | Patterns.cs:26:17:26:22 | break; | Patterns.cs:26:17:26:22 | break; | break | | Patterns.cs:27:13:27:24 | case ...: | Patterns.cs:27:18:27:23 | Int32 i3 | no-match | @@ -2969,6 +2974,7 @@ | Patterns.cs:28:17:28:47 | ...; | Patterns.cs:28:17:28:46 | call to method WriteLine | normal | | Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:28:35:28:45 | $"..." | normal | | Patterns.cs:28:37:28:40 | "int " | Patterns.cs:28:37:28:40 | "int " | normal | +| Patterns.cs:28:41:28:44 | {...} | Patterns.cs:28:41:28:44 | {...} | normal | | Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:42:28:43 | access to local variable i3 | normal | | Patterns.cs:29:17:29:22 | break; | Patterns.cs:29:17:29:22 | break; | break | | Patterns.cs:30:13:30:27 | case ...: | Patterns.cs:30:18:30:26 | String s2 | no-match | @@ -2979,6 +2985,7 @@ | Patterns.cs:31:17:31:50 | ...; | Patterns.cs:31:17:31:49 | call to method WriteLine | normal | | Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:31:35:31:48 | $"..." | normal | | Patterns.cs:31:37:31:43 | "string " | Patterns.cs:31:37:31:43 | "string " | normal | +| Patterns.cs:31:44:31:47 | {...} | Patterns.cs:31:44:31:47 | {...} | normal | | Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:45:31:46 | access to local variable s2 | normal | | Patterns.cs:32:17:32:22 | break; | Patterns.cs:32:17:32:22 | break; | break | | Patterns.cs:33:13:33:24 | case ...: | Patterns.cs:33:18:33:23 | Object v2 | no-match | @@ -3566,11 +3573,13 @@ | Switch.cs:158:13:158:49 | ...; | Switch.cs:158:13:158:48 | call to method WriteLine | normal | | Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:38:158:47 | $"..." | normal | | Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:40:158:43 | "a = " | normal | +| Switch.cs:158:44:158:46 | {...} | Switch.cs:158:44:158:46 | {...} | normal | | Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:45:158:45 | access to local variable s | normal | | Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:160:13:160:48 | call to method WriteLine | normal | | Switch.cs:160:13:160:49 | ...; | Switch.cs:160:13:160:48 | call to method WriteLine | normal | | Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:38:160:47 | $"..." | normal | | Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:40:160:43 | "b = " | normal | +| Switch.cs:160:44:160:46 | {...} | Switch.cs:160:44:160:46 | {...} | normal | | Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:45:160:45 | access to local variable s | normal | | TypeAccesses.cs:1:7:1:18 | call to constructor Object | TypeAccesses.cs:1:7:1:18 | call to constructor Object | normal | | TypeAccesses.cs:1:7:1:18 | {...} | TypeAccesses.cs:1:7:1:18 | {...} | normal | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 0ae9a8a1e35c..5b3860e04ede 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1679,12 +1679,14 @@ | Conditions.cs:147:13:147:49 | ...; | Conditions.cs:147:40:147:43 | "a = " | | | Conditions.cs:147:38:147:47 | $"..." | Conditions.cs:147:13:147:48 | call to method WriteLine | | | Conditions.cs:147:40:147:43 | "a = " | Conditions.cs:147:45:147:45 | access to local variable s | | -| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:38:147:47 | $"..." | | +| Conditions.cs:147:44:147:46 | {...} | Conditions.cs:147:38:147:47 | $"..." | | +| Conditions.cs:147:45:147:45 | access to local variable s | Conditions.cs:147:44:147:46 | {...} | | | Conditions.cs:149:13:149:48 | call to method WriteLine | Conditions.cs:143:10:143:12 | exit M11 (normal) | | | Conditions.cs:149:13:149:49 | ...; | Conditions.cs:149:40:149:43 | "b = " | | | Conditions.cs:149:38:149:47 | $"..." | Conditions.cs:149:13:149:48 | call to method WriteLine | | | Conditions.cs:149:40:149:43 | "b = " | Conditions.cs:149:45:149:45 | access to local variable s | | -| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:38:149:47 | $"..." | | +| Conditions.cs:149:44:149:46 | {...} | Conditions.cs:149:38:149:47 | $"..." | | +| Conditions.cs:149:45:149:45 | access to local variable s | Conditions.cs:149:44:149:46 | {...} | | | ExitMethods.cs:6:7:6:17 | call to constructor Object | ExitMethods.cs:6:7:6:17 | {...} | | | ExitMethods.cs:6:7:6:17 | enter ExitMethods | ExitMethods.cs:6:7:6:17 | call to constructor Object | | | ExitMethods.cs:6:7:6:17 | exit ExitMethods (normal) | ExitMethods.cs:6:7:6:17 | exit ExitMethods | | @@ -3528,7 +3530,8 @@ | Patterns.cs:10:13:10:43 | ...; | Patterns.cs:10:33:10:36 | "int " | | | Patterns.cs:10:31:10:41 | $"..." | Patterns.cs:10:13:10:42 | call to method WriteLine | | | Patterns.cs:10:33:10:36 | "int " | Patterns.cs:10:38:10:39 | access to local variable i1 | | -| Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:31:10:41 | $"..." | | +| Patterns.cs:10:37:10:40 | {...} | Patterns.cs:10:31:10:41 | $"..." | | +| Patterns.cs:10:38:10:39 | access to local variable i1 | Patterns.cs:10:37:10:40 | {...} | | | Patterns.cs:12:14:18:9 | if (...) ... | Patterns.cs:12:18:12:18 | access to local variable o | | | Patterns.cs:12:18:12:18 | access to local variable o | Patterns.cs:12:23:12:31 | String s1 | | | Patterns.cs:12:18:12:31 | [false] ... is ... | Patterns.cs:16:14:18:9 | if (...) ... | false | @@ -3540,7 +3543,8 @@ | Patterns.cs:14:13:14:46 | ...; | Patterns.cs:14:33:14:39 | "string " | | | Patterns.cs:14:31:14:44 | $"..." | Patterns.cs:14:13:14:45 | call to method WriteLine | | | Patterns.cs:14:33:14:39 | "string " | Patterns.cs:14:41:14:42 | access to local variable s1 | | -| Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:31:14:44 | $"..." | | +| Patterns.cs:14:40:14:43 | {...} | Patterns.cs:14:31:14:44 | $"..." | | +| Patterns.cs:14:41:14:42 | access to local variable s1 | Patterns.cs:14:40:14:43 | {...} | | | Patterns.cs:16:14:18:9 | if (...) ... | Patterns.cs:16:18:16:18 | access to local variable o | | | Patterns.cs:16:18:16:18 | access to local variable o | Patterns.cs:16:23:16:28 | Object v1 | | | Patterns.cs:16:18:16:28 | [false] ... is ... | Patterns.cs:20:9:38:9 | switch (...) {...} | false | @@ -3565,7 +3569,8 @@ | Patterns.cs:25:17:25:52 | ...; | Patterns.cs:25:37:25:45 | "positive " | | | Patterns.cs:25:35:25:50 | $"..." | Patterns.cs:25:17:25:51 | call to method WriteLine | | | Patterns.cs:25:37:25:45 | "positive " | Patterns.cs:25:47:25:48 | access to local variable i2 | | -| Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:35:25:50 | $"..." | | +| Patterns.cs:25:46:25:49 | {...} | Patterns.cs:25:35:25:50 | $"..." | | +| Patterns.cs:25:47:25:48 | access to local variable i2 | Patterns.cs:25:46:25:49 | {...} | | | Patterns.cs:26:17:26:22 | break; | Patterns.cs:40:9:42:9 | switch (...) {...} | break | | Patterns.cs:27:13:27:24 | case ...: | Patterns.cs:27:18:27:23 | Int32 i3 | | | Patterns.cs:27:18:27:23 | Int32 i3 | Patterns.cs:28:17:28:47 | ...; | match | @@ -3574,7 +3579,8 @@ | Patterns.cs:28:17:28:47 | ...; | Patterns.cs:28:37:28:40 | "int " | | | Patterns.cs:28:35:28:45 | $"..." | Patterns.cs:28:17:28:46 | call to method WriteLine | | | Patterns.cs:28:37:28:40 | "int " | Patterns.cs:28:42:28:43 | access to local variable i3 | | -| Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:35:28:45 | $"..." | | +| Patterns.cs:28:41:28:44 | {...} | Patterns.cs:28:35:28:45 | $"..." | | +| Patterns.cs:28:42:28:43 | access to local variable i3 | Patterns.cs:28:41:28:44 | {...} | | | Patterns.cs:29:17:29:22 | break; | Patterns.cs:40:9:42:9 | switch (...) {...} | break | | Patterns.cs:30:13:30:27 | case ...: | Patterns.cs:30:18:30:26 | String s2 | | | Patterns.cs:30:18:30:26 | String s2 | Patterns.cs:31:17:31:50 | ...; | match | @@ -3583,7 +3589,8 @@ | Patterns.cs:31:17:31:50 | ...; | Patterns.cs:31:37:31:43 | "string " | | | Patterns.cs:31:35:31:48 | $"..." | Patterns.cs:31:17:31:49 | call to method WriteLine | | | Patterns.cs:31:37:31:43 | "string " | Patterns.cs:31:45:31:46 | access to local variable s2 | | -| Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:35:31:48 | $"..." | | +| Patterns.cs:31:44:31:47 | {...} | Patterns.cs:31:35:31:48 | $"..." | | +| Patterns.cs:31:45:31:46 | access to local variable s2 | Patterns.cs:31:44:31:47 | {...} | | | Patterns.cs:32:17:32:22 | break; | Patterns.cs:40:9:42:9 | switch (...) {...} | break | | Patterns.cs:33:13:33:24 | case ...: | Patterns.cs:33:18:33:23 | Object v2 | | | Patterns.cs:33:18:33:23 | Object v2 | Patterns.cs:34:17:34:22 | break; | match | @@ -4130,12 +4137,14 @@ | Switch.cs:158:13:158:49 | ...; | Switch.cs:158:40:158:43 | "a = " | | | Switch.cs:158:38:158:47 | $"..." | Switch.cs:158:13:158:48 | call to method WriteLine | | | Switch.cs:158:40:158:43 | "a = " | Switch.cs:158:45:158:45 | access to local variable s | | -| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:38:158:47 | $"..." | | +| Switch.cs:158:44:158:46 | {...} | Switch.cs:158:38:158:47 | $"..." | | +| Switch.cs:158:45:158:45 | access to local variable s | Switch.cs:158:44:158:46 | {...} | | | Switch.cs:160:13:160:48 | call to method WriteLine | Switch.cs:154:10:154:12 | exit M15 (normal) | | | Switch.cs:160:13:160:49 | ...; | Switch.cs:160:40:160:43 | "b = " | | | Switch.cs:160:38:160:47 | $"..." | Switch.cs:160:13:160:48 | call to method WriteLine | | | Switch.cs:160:40:160:43 | "b = " | Switch.cs:160:45:160:45 | access to local variable s | | -| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:38:160:47 | $"..." | | +| Switch.cs:160:44:160:46 | {...} | Switch.cs:160:38:160:47 | $"..." | | +| Switch.cs:160:45:160:45 | access to local variable s | Switch.cs:160:44:160:46 | {...} | | | TypeAccesses.cs:1:7:1:18 | call to constructor Object | TypeAccesses.cs:1:7:1:18 | {...} | | | TypeAccesses.cs:1:7:1:18 | enter TypeAccesses | TypeAccesses.cs:1:7:1:18 | call to constructor Object | | | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses (normal) | TypeAccesses.cs:1:7:1:18 | exit TypeAccesses | | diff --git a/csharp/ql/test/library-tests/csharp11/PrintAst.expected b/csharp/ql/test/library-tests/csharp11/PrintAst.expected index b10e2096489b..3a3f44974231 100644 --- a/csharp/ql/test/library-tests/csharp11/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp11/PrintAst.expected @@ -1332,14 +1332,15 @@ Strings.cs: # 8| 0: [ReturnStmt] return ...; # 8| 0: [InterpolatedStringExpr] $"..." # 8| 0: [StringLiteralUtf16] "This is my int " -# 8| 1: [SwitchExpr] ... switch { ... } -# 8| -1: [ParameterAccess] access to parameter x -# 10| 0: [SwitchCaseExpr] ... => ... -# 10| 0: [ConstantPatternExpr,IntLiteral] 42 -# 10| 2: [StringLiteralUtf16] "forty two" -# 11| 1: [SwitchCaseExpr] ... => ... -# 11| 0: [DiscardPatternExpr] _ -# 11| 2: [StringLiteralUtf16] "something else" +# 8| 1: [InterpolatedStringInsertExpr] {...} +# 8| 0: [SwitchExpr] ... switch { ... } +# 8| -1: [ParameterAccess] access to parameter x +# 10| 0: [SwitchCaseExpr] ... => ... +# 10| 0: [ConstantPatternExpr,IntLiteral] 42 +# 10| 2: [StringLiteralUtf16] "forty two" +# 11| 1: [SwitchCaseExpr] ... => ... +# 11| 0: [DiscardPatternExpr] _ +# 11| 2: [StringLiteralUtf16] "something else" # 12| 2: [StringLiteralUtf16] "." # 15| 6: [Method] M2 # 15| -1: [TypeMention] Void @@ -1359,7 +1360,8 @@ Strings.cs: # 26| 1: [InterpolatedStringExpr] $"..." # 27| 0: [StringLiteralUtf16] "The nested message # 27| is \"" -# 28| 1: [LocalVariableAccess] access to local variable message1 +# 28| 1: [InterpolatedStringInsertExpr] {...} +# 28| 0: [LocalVariableAccess] access to local variable message1 # 28| 2: [StringLiteralUtf16] "\" and everything # 28| spans multiple lines." # 33| 2: [LocalVariableDeclStmt] ... ...; @@ -1368,10 +1370,12 @@ Strings.cs: # 33| 0: [LocalVariableAccess] access to local variable message3 # 33| 1: [InterpolatedStringExpr] $"..." # 34| 0: [StringLiteralUtf16] "Show no curly braces: " -# 34| 1: [LocalVariableAccess] access to local variable message1 +# 34| 1: [InterpolatedStringInsertExpr] {...} +# 34| 0: [LocalVariableAccess] access to local variable message1 # 34| 2: [StringLiteralUtf16] " # 34| Show matching set of curly braces: {" -# 35| 3: [LocalVariableAccess] access to local variable message2 +# 35| 3: [InterpolatedStringInsertExpr] {...} +# 35| 0: [LocalVariableAccess] access to local variable message2 # 35| 4: [StringLiteralUtf16] "}" # 40| 7: [Method] M3 # 40| -1: [TypeMention] Void diff --git a/csharp/ql/test/library-tests/csharp6/InterpolatedStringExpr.expected b/csharp/ql/test/library-tests/csharp6/InterpolatedStringExpr.expected index d10365546bd9..a7c904f56867 100644 --- a/csharp/ql/test/library-tests/csharp6/InterpolatedStringExpr.expected +++ b/csharp/ql/test/library-tests/csharp6/InterpolatedStringExpr.expected @@ -1,14 +1,14 @@ -| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:26:25:36 | nameof(...) | +| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:25:25:37 | {...} | | csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:38:25:41 | " is " | -| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:43:25:45 | access to local variable foo | +| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:42:25:46 | {...} | | csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:47:25:52 | ", and " | -| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:54:25:64 | nameof(...) | +| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:53:25:65 | {...} | | csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:66:25:77 | " has length " | -| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:79:25:94 | ... ?? ... | -| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:20:27:30 | nameof(...) | +| csharp6.cs:25:23:25:96 | $"..." | csharp6.cs:25:78:25:95 | {...} | +| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:19:27:31 | {...} | | csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:32:27:35 | " is " | -| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:37:27:39 | access to local variable foo | +| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:36:27:40 | {...} | | csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:41:27:46 | ", and " | -| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:48:27:58 | nameof(...) | +| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:47:27:59 | {...} | | csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:60:27:71 | " has length " | -| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:73:27:88 | ... ?? ... | +| csharp6.cs:27:16:27:90 | $"..." | csharp6.cs:27:72:27:89 | {...} | diff --git a/csharp/ql/test/library-tests/csharp6/PrintAst.expected b/csharp/ql/test/library-tests/csharp6/PrintAst.expected index 892ad6dd4b15..424a18bcb023 100644 --- a/csharp/ql/test/library-tests/csharp6/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp6/PrintAst.expected @@ -30,33 +30,41 @@ csharp6.cs: # 25| 1: [ExprStmt] ...; # 25| 0: [MethodCall] call to method WriteLine # 25| 0: [InterpolatedStringExpr] $"..." -# 25| 0: [NameOfExpr] nameof(...) -# 25| 0: [LocalVariableAccess] access to local variable foo +# 25| 0: [InterpolatedStringInsertExpr] {...} +# 25| 0: [NameOfExpr] nameof(...) +# 25| 0: [LocalVariableAccess] access to local variable foo # 25| 1: [StringLiteralUtf16] " is " -# 25| 2: [LocalVariableAccess] access to local variable foo +# 25| 2: [InterpolatedStringInsertExpr] {...} +# 25| 0: [LocalVariableAccess] access to local variable foo # 25| 3: [StringLiteralUtf16] ", and " -# 25| 4: [NameOfExpr] nameof(...) -# 25| 0: [LocalVariableAccess] access to local variable bar +# 25| 4: [InterpolatedStringInsertExpr] {...} +# 25| 0: [NameOfExpr] nameof(...) +# 25| 0: [LocalVariableAccess] access to local variable bar # 25| 5: [StringLiteralUtf16] " has length " -# 25| 6: [NullCoalescingExpr] ... ?? ... -# 25| 0: [PropertyCall] access to property Length -# 25| -1: [LocalVariableAccess] access to local variable bar -# 25| 1: [IntLiteral] 0 +# 25| 6: [InterpolatedStringInsertExpr] {...} +# 25| 0: [NullCoalescingExpr] ... ?? ... +# 25| 0: [PropertyCall] access to property Length +# 25| -1: [LocalVariableAccess] access to local variable bar +# 25| 1: [IntLiteral] 0 # 27| 2: [ExprStmt] ...; # 27| 0: [MethodCall] call to method Fn # 27| 0: [InterpolatedStringExpr] $"..." -# 27| 0: [NameOfExpr] nameof(...) -# 27| 0: [LocalVariableAccess] access to local variable foo +# 27| 0: [InterpolatedStringInsertExpr] {...} +# 27| 0: [NameOfExpr] nameof(...) +# 27| 0: [LocalVariableAccess] access to local variable foo # 27| 1: [StringLiteralUtf16] " is " -# 27| 2: [LocalVariableAccess] access to local variable foo +# 27| 2: [InterpolatedStringInsertExpr] {...} +# 27| 0: [LocalVariableAccess] access to local variable foo # 27| 3: [StringLiteralUtf16] ", and " -# 27| 4: [NameOfExpr] nameof(...) -# 27| 0: [LocalVariableAccess] access to local variable bar +# 27| 4: [InterpolatedStringInsertExpr] {...} +# 27| 0: [NameOfExpr] nameof(...) +# 27| 0: [LocalVariableAccess] access to local variable bar # 27| 5: [StringLiteralUtf16] " has length " -# 27| 6: [NullCoalescingExpr] ... ?? ... -# 27| 0: [PropertyCall] access to property Length -# 27| -1: [LocalVariableAccess] access to local variable bar -# 27| 1: [IntLiteral] 0 +# 27| 6: [InterpolatedStringInsertExpr] {...} +# 27| 0: [NullCoalescingExpr] ... ?? ... +# 27| 0: [PropertyCall] access to property Length +# 27| -1: [LocalVariableAccess] access to local variable bar +# 27| 1: [IntLiteral] 0 # 29| 3: [LocalVariableDeclStmt] ... ...; # 29| 0: [LocalVariableDeclAndInitExpr] Nullable anythingInBar = ... # 29| -1: [TypeMention] bool? diff --git a/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected b/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected index d55d5d279ada..70bfee85c04b 100644 --- a/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected @@ -110,4 +110,5 @@ csharp73.cs: # 51| 0: [TypeMention] Console # 51| 0: [InterpolatedStringExpr] $"..." # 51| 0: [StringLiteralUtf16] "x is " -# 51| 1: [LocalVariableAccess] access to local variable x +# 51| 1: [InterpolatedStringInsertExpr] {...} +# 51| 0: [LocalVariableAccess] access to local variable x diff --git a/csharp/ql/test/library-tests/csharp7/IsFlow.expected b/csharp/ql/test/library-tests/csharp7/IsFlow.expected index b3e283528457..ce37b655bb85 100644 --- a/csharp/ql/test/library-tests/csharp7/IsFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/IsFlow.expected @@ -24,7 +24,8 @@ | CSharp7.cs:255:17:255:45 | ...; | CSharp7.cs:255:37:255:38 | "x " | semmle.label | successor | | CSharp7.cs:255:35:255:43 | $"..." | CSharp7.cs:255:17:255:44 | call to method WriteLine | semmle.label | successor | | CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:40:255:41 | access to local variable s4 | semmle.label | successor | -| CSharp7.cs:255:40:255:41 | access to local variable s4 | CSharp7.cs:255:35:255:43 | $"..." | semmle.label | successor | +| CSharp7.cs:255:39:255:42 | {...} | CSharp7.cs:255:35:255:43 | $"..." | semmle.label | successor | +| CSharp7.cs:255:40:255:41 | access to local variable s4 | CSharp7.cs:255:39:255:42 | {...} | semmle.label | successor | | CSharp7.cs:256:17:256:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break | | CSharp7.cs:257:13:257:36 | case ...: | CSharp7.cs:257:18:257:23 | Int32 i2 | semmle.label | successor | | CSharp7.cs:257:18:257:23 | Int32 i2 | CSharp7.cs:257:30:257:31 | access to local variable i2 | semmle.label | match | @@ -37,7 +38,8 @@ | CSharp7.cs:258:17:258:52 | ...; | CSharp7.cs:258:37:258:45 | "positive " | semmle.label | successor | | CSharp7.cs:258:35:258:50 | $"..." | CSharp7.cs:258:17:258:51 | call to method WriteLine | semmle.label | successor | | CSharp7.cs:258:37:258:45 | "positive " | CSharp7.cs:258:47:258:48 | access to local variable i2 | semmle.label | successor | -| CSharp7.cs:258:47:258:48 | access to local variable i2 | CSharp7.cs:258:35:258:50 | $"..." | semmle.label | successor | +| CSharp7.cs:258:46:258:49 | {...} | CSharp7.cs:258:35:258:50 | $"..." | semmle.label | successor | +| CSharp7.cs:258:47:258:48 | access to local variable i2 | CSharp7.cs:258:46:258:49 | {...} | semmle.label | successor | | CSharp7.cs:259:17:259:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break | | CSharp7.cs:260:13:260:24 | case ...: | CSharp7.cs:260:18:260:23 | Int32 i3 | semmle.label | successor | | CSharp7.cs:260:18:260:23 | Int32 i3 | CSharp7.cs:261:17:261:47 | ...; | semmle.label | match | @@ -46,7 +48,8 @@ | CSharp7.cs:261:17:261:47 | ...; | CSharp7.cs:261:37:261:40 | "int " | semmle.label | successor | | CSharp7.cs:261:35:261:45 | $"..." | CSharp7.cs:261:17:261:46 | call to method WriteLine | semmle.label | successor | | CSharp7.cs:261:37:261:40 | "int " | CSharp7.cs:261:42:261:43 | access to local variable i3 | semmle.label | successor | -| CSharp7.cs:261:42:261:43 | access to local variable i3 | CSharp7.cs:261:35:261:45 | $"..." | semmle.label | successor | +| CSharp7.cs:261:41:261:44 | {...} | CSharp7.cs:261:35:261:45 | $"..." | semmle.label | successor | +| CSharp7.cs:261:42:261:43 | access to local variable i3 | CSharp7.cs:261:41:261:44 | {...} | semmle.label | successor | | CSharp7.cs:262:17:262:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break | | CSharp7.cs:263:13:263:27 | case ...: | CSharp7.cs:263:18:263:26 | String s2 | semmle.label | successor | | CSharp7.cs:263:18:263:26 | String s2 | CSharp7.cs:264:17:264:50 | ...; | semmle.label | match | @@ -55,7 +58,8 @@ | CSharp7.cs:264:17:264:50 | ...; | CSharp7.cs:264:37:264:43 | "string " | semmle.label | successor | | CSharp7.cs:264:35:264:48 | $"..." | CSharp7.cs:264:17:264:49 | call to method WriteLine | semmle.label | successor | | CSharp7.cs:264:37:264:43 | "string " | CSharp7.cs:264:45:264:46 | access to local variable s2 | semmle.label | successor | -| CSharp7.cs:264:45:264:46 | access to local variable s2 | CSharp7.cs:264:35:264:48 | $"..." | semmle.label | successor | +| CSharp7.cs:264:44:264:47 | {...} | CSharp7.cs:264:35:264:48 | $"..." | semmle.label | successor | +| CSharp7.cs:264:45:264:46 | access to local variable s2 | CSharp7.cs:264:44:264:47 | {...} | semmle.label | successor | | CSharp7.cs:265:17:265:22 | break; | CSharp7.cs:230:10:230:13 | exit Test (normal) | semmle.label | break | | CSharp7.cs:266:13:266:26 | case ...: | CSharp7.cs:266:18:266:23 | access to type Double | semmle.label | successor | | CSharp7.cs:266:18:266:23 | access to type Double | CSharp7.cs:267:17:267:44 | ...; | semmle.label | match | diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index 4a16e2491dfe..1bba9f6dd8ba 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -254,7 +254,8 @@ | CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [true] ... && ... | | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." | -| CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:31:235:41 | $"..." | +| CSharp7.cs:235:37:235:40 | {...} | CSharp7.cs:235:31:235:41 | $"..." | +| CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:37:235:40 | {...} | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:241:18:241:18 | access to local variable o | @@ -262,7 +263,8 @@ | CSharp7.cs:237:23:237:31 | String s1 | CSharp7.cs:237:23:237:31 | SSA def(s1) | | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." | -| CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:31:239:44 | $"..." | +| CSharp7.cs:239:40:239:43 | {...} | CSharp7.cs:239:31:239:44 | $"..." | +| CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:40:239:43 | {...} | | CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | | CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:244:18:244:18 | access to local variable o | | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | @@ -283,21 +285,25 @@ | CSharp7.cs:254:32:254:40 | SSA def(s4) | CSharp7.cs:255:40:255:41 | access to local variable s4 | | CSharp7.cs:254:32:254:40 | String s4 | CSharp7.cs:254:32:254:40 | SSA def(s4) | | CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:35:255:43 | $"..." | -| CSharp7.cs:255:40:255:41 | access to local variable s4 | CSharp7.cs:255:35:255:43 | $"..." | +| CSharp7.cs:255:39:255:42 | {...} | CSharp7.cs:255:35:255:43 | $"..." | +| CSharp7.cs:255:40:255:41 | access to local variable s4 | CSharp7.cs:255:39:255:42 | {...} | | CSharp7.cs:257:18:257:23 | Int32 i2 | CSharp7.cs:257:18:257:23 | SSA def(i2) | | CSharp7.cs:257:18:257:23 | SSA def(i2) | CSharp7.cs:257:30:257:31 | access to local variable i2 | | CSharp7.cs:257:30:257:31 | access to local variable i2 | CSharp7.cs:257:30:257:35 | ... > ... | | CSharp7.cs:257:30:257:31 | access to local variable i2 | CSharp7.cs:258:47:258:48 | access to local variable i2 | | CSharp7.cs:258:37:258:45 | "positive " | CSharp7.cs:258:35:258:50 | $"..." | -| CSharp7.cs:258:47:258:48 | access to local variable i2 | CSharp7.cs:258:35:258:50 | $"..." | +| CSharp7.cs:258:46:258:49 | {...} | CSharp7.cs:258:35:258:50 | $"..." | +| CSharp7.cs:258:47:258:48 | access to local variable i2 | CSharp7.cs:258:46:258:49 | {...} | | CSharp7.cs:260:18:260:23 | Int32 i3 | CSharp7.cs:260:18:260:23 | SSA def(i3) | | CSharp7.cs:260:18:260:23 | SSA def(i3) | CSharp7.cs:261:42:261:43 | access to local variable i3 | | CSharp7.cs:261:37:261:40 | "int " | CSharp7.cs:261:35:261:45 | $"..." | -| CSharp7.cs:261:42:261:43 | access to local variable i3 | CSharp7.cs:261:35:261:45 | $"..." | +| CSharp7.cs:261:41:261:44 | {...} | CSharp7.cs:261:35:261:45 | $"..." | +| CSharp7.cs:261:42:261:43 | access to local variable i3 | CSharp7.cs:261:41:261:44 | {...} | | CSharp7.cs:263:18:263:26 | SSA def(s2) | CSharp7.cs:264:45:264:46 | access to local variable s2 | | CSharp7.cs:263:18:263:26 | String s2 | CSharp7.cs:263:18:263:26 | SSA def(s2) | | CSharp7.cs:264:37:264:43 | "string " | CSharp7.cs:264:35:264:48 | $"..." | -| CSharp7.cs:264:45:264:46 | access to local variable s2 | CSharp7.cs:264:35:264:48 | $"..." | +| CSharp7.cs:264:44:264:47 | {...} | CSharp7.cs:264:35:264:48 | $"..." | +| CSharp7.cs:264:45:264:46 | access to local variable s2 | CSharp7.cs:264:44:264:47 | {...} | | CSharp7.cs:282:13:282:16 | access to local variable dict | CSharp7.cs:282:13:282:48 | SSA def(dict) | | CSharp7.cs:282:13:282:48 | SSA def(dict) | CSharp7.cs:283:20:283:23 | access to local variable dict | | CSharp7.cs:282:20:282:48 | object creation of type Dictionary | CSharp7.cs:282:13:282:16 | access to local variable dict | diff --git a/csharp/ql/test/library-tests/csharp7/PrintAst.expected b/csharp/ql/test/library-tests/csharp7/PrintAst.expected index e5d009e0df63..bf0b07abbeb8 100644 --- a/csharp/ql/test/library-tests/csharp7/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp7/PrintAst.expected @@ -727,7 +727,8 @@ CSharp7.cs: # 235| 0: [TypeMention] Console # 235| 0: [InterpolatedStringExpr] $"..." # 235| 0: [StringLiteralUtf16] "int " -# 235| 1: [LocalVariableAccess] access to local variable i1 +# 235| 1: [InterpolatedStringInsertExpr] {...} +# 235| 0: [LocalVariableAccess] access to local variable i1 # 237| 2: [IfStmt] if (...) ... # 237| 0: [IsExpr] ... is ... # 237| 0: [LocalVariableAccess] access to local variable o @@ -740,7 +741,8 @@ CSharp7.cs: # 239| 0: [TypeMention] Console # 239| 0: [InterpolatedStringExpr] $"..." # 239| 0: [StringLiteralUtf16] "string " -# 239| 1: [LocalVariableAccess] access to local variable s1 +# 239| 1: [InterpolatedStringInsertExpr] {...} +# 239| 0: [LocalVariableAccess] access to local variable s1 # 241| 2: [IfStmt] if (...) ... # 241| 0: [IsExpr] ... is ... # 241| 0: [LocalVariableAccess] access to local variable o @@ -775,7 +777,8 @@ CSharp7.cs: # 255| 0: [TypeMention] Console # 255| 0: [InterpolatedStringExpr] $"..." # 255| 0: [StringLiteralUtf16] "x " -# 255| 1: [LocalVariableAccess] access to local variable s4 +# 255| 1: [InterpolatedStringInsertExpr] {...} +# 255| 0: [LocalVariableAccess] access to local variable s4 # 256| 6: [BreakStmt] break; # 257| 7: [CaseStmt] case ...: # 257| 0: [VariablePatternExpr] Int32 i2 @@ -789,7 +792,8 @@ CSharp7.cs: # 258| 0: [TypeMention] Console # 258| 0: [InterpolatedStringExpr] $"..." # 258| 0: [StringLiteralUtf16] "positive " -# 258| 1: [LocalVariableAccess] access to local variable i2 +# 258| 1: [InterpolatedStringInsertExpr] {...} +# 258| 0: [LocalVariableAccess] access to local variable i2 # 259| 9: [BreakStmt] break; # 260| 10: [CaseStmt] case ...: # 260| 0: [VariablePatternExpr] Int32 i3 @@ -800,7 +804,8 @@ CSharp7.cs: # 261| 0: [TypeMention] Console # 261| 0: [InterpolatedStringExpr] $"..." # 261| 0: [StringLiteralUtf16] "int " -# 261| 1: [LocalVariableAccess] access to local variable i3 +# 261| 1: [InterpolatedStringInsertExpr] {...} +# 261| 0: [LocalVariableAccess] access to local variable i3 # 262| 12: [BreakStmt] break; # 263| 13: [CaseStmt] case ...: # 263| 0: [VariablePatternExpr] String s2 @@ -811,7 +816,8 @@ CSharp7.cs: # 264| 0: [TypeMention] Console # 264| 0: [InterpolatedStringExpr] $"..." # 264| 0: [StringLiteralUtf16] "string " -# 264| 1: [LocalVariableAccess] access to local variable s2 +# 264| 1: [InterpolatedStringInsertExpr] {...} +# 264| 0: [LocalVariableAccess] access to local variable s2 # 265| 15: [BreakStmt] break; # 266| 16: [CaseStmt] case ...: # 266| 0: [TypeAccessPatternExpr] access to type Double diff --git a/csharp/ql/test/library-tests/csharp8/PrintAst.expected b/csharp/ql/test/library-tests/csharp8/PrintAst.expected index c33374e4761d..4ec30c915b3a 100644 --- a/csharp/ql/test/library-tests/csharp8/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp8/PrintAst.expected @@ -4,12 +4,14 @@ AlternateInterpolatedStrings.cs: # 5| -1: [TypeMention] string # 5| 1: [InterpolatedStringExpr] $"..." # 5| 0: [StringLiteralUtf16] "C:" -# 5| 1: [IntLiteral] 12 +# 5| 1: [InterpolatedStringInsertExpr] {...} +# 5| 0: [IntLiteral] 12 # 6| 6: [Field] s2 # 6| -1: [TypeMention] string # 6| 1: [InterpolatedStringExpr] $"..." # 6| 0: [StringLiteralUtf16] "C:" -# 6| 1: [IntLiteral] 12 +# 6| 1: [InterpolatedStringInsertExpr] {...} +# 6| 0: [IntLiteral] 12 AsyncStreams.cs: # 6| [Class] AsyncStreams # 8| 5: [Method] Items diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index a1ecbd0a2123..e3b89de20096 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -1008,8 +1008,9 @@ Record.cs: # 49| 0: [LocalVariableAccess] access to local variable s # 50| 2: [ReturnStmt] return ...; # 50| 0: [InterpolatedStringExpr] $"..." -# 50| 0: [MethodCall] call to method ToString -# 50| -1: [LocalVariableAccess] access to local variable s +# 50| 0: [InterpolatedStringInsertExpr] {...} +# 50| 0: [MethodCall] call to method ToString +# 50| -1: [LocalVariableAccess] access to local variable s # 50| 1: [StringLiteralUtf16] " is a dog" # 54| [RecordClass] R1 # 54| 12: [NEOperator] != diff --git a/csharp/ql/test/library-tests/dataflow/implicittostring/PrintAst.expected b/csharp/ql/test/library-tests/dataflow/implicittostring/PrintAst.expected index bf2a515a8895..cd7658f6f5e9 100644 --- a/csharp/ql/test/library-tests/dataflow/implicittostring/PrintAst.expected +++ b/csharp/ql/test/library-tests/dataflow/implicittostring/PrintAst.expected @@ -68,8 +68,9 @@ implicitToString.cs: # 32| 0: [LocalVariableAccess] access to local variable x2 # 32| 1: [InterpolatedStringExpr] $"..." # 32| 0: [StringLiteralUtf16] "Hello " -# 32| 1: [MethodCall] call to method ToString -# 32| -1: [LocalVariableAccess] access to local variable x1 +# 32| 1: [InterpolatedStringInsertExpr] {...} +# 32| 0: [MethodCall] call to method ToString +# 32| -1: [LocalVariableAccess] access to local variable x1 # 33| 2: [ExprStmt] ...; # 33| 0: [MethodCall] call to method Sink # 33| 0: [LocalVariableAccess] access to local variable x2 @@ -88,8 +89,9 @@ implicitToString.cs: # 39| 0: [LocalVariableAccess] access to local variable x2 # 39| 1: [InterpolatedStringExpr] $"..." # 39| 0: [StringLiteralUtf16] "Hello " -# 39| 1: [MethodCall] call to method ToString -# 39| -1: [LocalVariableAccess] access to local variable x1 +# 39| 1: [InterpolatedStringInsertExpr] {...} +# 39| 0: [MethodCall] call to method ToString +# 39| -1: [LocalVariableAccess] access to local variable x1 # 40| 2: [ExprStmt] ...; # 40| 0: [MethodCall] call to method Sink # 40| 0: [LocalVariableAccess] access to local variable x2 diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index ea0ae7f9da73..7187280f7555 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -547,12 +547,14 @@ | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | | LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:18 | access to local variable sink69 | | LocalDataFlow.cs:273:24:273:28 | "test " | LocalDataFlow.cs:273:22:273:36 | $"..." | -| LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:273:29:273:35 | {...} | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | LocalDataFlow.cs:273:29:273:35 | {...} | | LocalDataFlow.cs:277:9:277:16 | access to local variable nonSink0 | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | | LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:16 | access to local variable nonSink0 | | LocalDataFlow.cs:277:22:277:26 | "test " | LocalDataFlow.cs:277:20:277:37 | $"..." | -| LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:277:27:277:36 | {...} | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | LocalDataFlow.cs:277:27:277:36 | {...} | | LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | | LocalDataFlow.cs:281:13:281:18 | access to local variable sink70 | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | @@ -1237,8 +1239,10 @@ | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | Splitting.cs:56:9:56:9 | access to local variable x | | Splitting.cs:56:15:56:15 | [b (line 46): false] "c" | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | | Splitting.cs:56:15:56:15 | [b (line 46): true] "c" | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | -| Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | -| Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | +| Splitting.cs:56:16:56:18 | [b (line 46): false] {...} | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | +| Splitting.cs:56:16:56:18 | [b (line 46): true] {...} | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | +| Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:16:56:18 | [b (line 46): false] {...} | +| Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:16:56:18 | [b (line 46): true] {...} | | Splitting.cs:57:13:57:24 | [b (line 46): false] access to field Item1 | Splitting.cs:57:9:57:9 | access to local variable x | | Splitting.cs:57:13:57:24 | [b (line 46): true] access to field Item1 | Splitting.cs:57:9:57:9 | access to local variable x | | Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | From acec97db94fe79f3928f5d58b62045436be58f88 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 21 Mar 2025 13:32:44 +0100 Subject: [PATCH 5/9] C#: Add change-note. --- csharp/ql/lib/change-notes/2025-03-21-string-interpolation.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2025-03-21-string-interpolation.md diff --git a/csharp/ql/lib/change-notes/2025-03-21-string-interpolation.md b/csharp/ql/lib/change-notes/2025-03-21-string-interpolation.md new file mode 100644 index 000000000000..3507d35b5135 --- /dev/null +++ b/csharp/ql/lib/change-notes/2025-03-21-string-interpolation.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The *alignment* and *format* clauses in string interpolation expressions are now extracted. That is, in `$"Hello {name,align:format}"` *name*, *align* and *format* are extracted as children of the string interpolation *insert* `{name,align:format}`. From d9fb13790994686a480cdf824b53901bbdf4acd3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 24 Mar 2025 11:56:00 +0100 Subject: [PATCH 6/9] C#: Add upgrade- and downgrade scripts. --- .../expressions.ql | 13 + .../old.dbscheme | 1460 +++++++++++++++++ .../semmlecode.csharp.dbscheme | 1459 ++++++++++++++++ .../upgrade.properties | 3 + .../old.dbscheme | 1459 ++++++++++++++++ .../semmlecode.csharp.dbscheme | 1460 +++++++++++++++++ .../upgrade.properties | 2 + 7 files changed, 5856 insertions(+) create mode 100644 csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql create mode 100644 csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/old.dbscheme create mode 100644 csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/semmlecode.csharp.dbscheme create mode 100644 csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties create mode 100644 csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/old.dbscheme create mode 100644 csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/semmlecode.csharp.dbscheme create mode 100644 csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql new file mode 100644 index 000000000000..4f516d1d5cba --- /dev/null +++ b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql @@ -0,0 +1,13 @@ +class Expression extends @expr { + string toString() { none() } +} + +class TypeOrRef extends @type_or_ref { + string toString() { none() } +} + +from Expression e, int k, int kind, TypeOrRef t +where + expressions(e, k, t) and + if k = 138 then kind = 106 else kind = k +select e, kind, t diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/old.dbscheme b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/old.dbscheme new file mode 100644 index 000000000000..66044cfa5bbf --- /dev/null +++ b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/old.dbscheme @@ -0,0 +1,1460 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line 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, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/semmlecode.csharp.dbscheme b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/semmlecode.csharp.dbscheme new file mode 100644 index 000000000000..a2bda57dbc6e --- /dev/null +++ b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/semmlecode.csharp.dbscheme @@ -0,0 +1,1459 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line 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, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties new file mode 100644 index 000000000000..9e9a659b10a3 --- /dev/null +++ b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties @@ -0,0 +1,3 @@ +description: Remove `interpolated_string_insert_expr` kind. +compatibility: partial +expressions.rel: run expressions.qlo diff --git a/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/old.dbscheme b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/old.dbscheme new file mode 100644 index 000000000000..a2bda57dbc6e --- /dev/null +++ b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/old.dbscheme @@ -0,0 +1,1459 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line 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, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/semmlecode.csharp.dbscheme b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/semmlecode.csharp.dbscheme new file mode 100644 index 000000000000..66044cfa5bbf --- /dev/null +++ b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/semmlecode.csharp.dbscheme @@ -0,0 +1,1460 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line 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, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties new file mode 100644 index 000000000000..1989c9c8847b --- /dev/null +++ b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties @@ -0,0 +1,2 @@ +description: Add `interpolated_string_insert_expr` kind. +compatibility: partial From 00753a1fe40a8de525d54e77163ba904166f4b9c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 28 Mar 2025 14:41:59 +0100 Subject: [PATCH 7/9] C#: Address review comments. --- .../stringinterpolation/stringInterpolation.ql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql b/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql index 21b33b12b56d..f4d683858105 100644 --- a/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql +++ b/csharp/ql/test/library-tests/stringinterpolation/stringInterpolation.ql @@ -1,11 +1,9 @@ import csharp -query predicate inserts(InterpolatedStringExpr expr, Expr e) { - expr.getAnInsert() = e // and inSpecificSource(expr) -} +query predicate inserts(InterpolatedStringExpr expr, Expr e) { expr.getAnInsert() = e } query predicate texts(InterpolatedStringExpr expr, StringLiteral literal) { - expr.getAText() = literal // and inSpecificSource(expr) + expr.getAText() = literal } query predicate interpolationInsertsWithAlign(InterpolatedStringExpr expr, Expr insert, Expr align) { From e30fed6eecf67a28bdc5ca06939d0cc68cee6b73 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 31 Mar 2025 11:30:40 +0200 Subject: [PATCH 8/9] C#: Improve upgrade script. --- .../string_interpol_insert.ql | 57 +++++++++++++++++++ .../upgrade.properties | 4 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/string_interpol_insert.ql diff --git a/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/string_interpol_insert.ql b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/string_interpol_insert.ql new file mode 100644 index 000000000000..2df164b2842e --- /dev/null +++ b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/string_interpol_insert.ql @@ -0,0 +1,57 @@ +class Expr extends @expr { + string toString() { none() } +} + +class TypeOrRef extends @type_or_ref { + string toString() { none() } +} + +class StringLiteral extends Expr, @string_literal_expr { } + +class InterpolatedStringExpr extends Expr, @interpolated_string_expr { } + +class StringInterpolationInsert extends Expr, @element { + StringInterpolationInsert() { + expressions(this, _, _) and + expr_parent(this, _, any(InterpolatedStringExpr x)) and + not this instanceof StringLiteral + } +} + +newtype TAddedElement = TInsert(StringInterpolationInsert e) + +module Fresh = QlBuiltins::NewEntity; + +class TNewExpr = @expr or Fresh::EntityId; + +class NewExpr extends TNewExpr { + string toString() { none() } +} + +query predicate new_expressions(NewExpr id, int kind, TypeOrRef t) { + expressions(id, kind, t) + or + exists(StringInterpolationInsert e | + // The type of `e` is just copied even though a null type would be preferred. + expressions(e, _, t) and + Fresh::map(TInsert(e)) = id and + kind = 138 + ) +} + +query predicate new_expr_parent(NewExpr id, int child, NewExpr parent) { + // Keep all parent child relationships except for string interpolation inserts + expr_parent(id, child, parent) and not id instanceof StringInterpolationInsert + or + exists(StringInterpolationInsert e, int child0, NewExpr p0, NewExpr new_id | + expr_parent(e, child0, p0) and new_id = Fresh::map(TInsert(e)) + | + id = new_id and + child = child0 and + parent = p0 + or + id = e and + child = 0 and + parent = new_id + ) +} diff --git a/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties index 1989c9c8847b..ef7a5cbf3436 100644 --- a/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties +++ b/csharp/ql/lib/upgrades/a2bda57dbc6eea94c50128522aae536e8edd5a3c/upgrade.properties @@ -1,2 +1,4 @@ description: Add `interpolated_string_insert_expr` kind. -compatibility: partial +compatibility: backwards +expressions.rel: run string_interpol_insert.qlo new_expressions +expr_parent.rel: run string_interpol_insert.qlo new_expr_parent From 8e1282bfde17e8a35194edf9e6adc90d2ff259ec Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 31 Mar 2025 13:39:03 +0200 Subject: [PATCH 9/9] C#: Improve downgrade script. --- .../expressions.ql | 13 ------- .../string_interpol_insert.ql | 39 +++++++++++++++++++ .../upgrade.properties | 5 ++- 3 files changed, 42 insertions(+), 15 deletions(-) delete mode 100644 csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql create mode 100644 csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/string_interpol_insert.ql diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql deleted file mode 100644 index 4f516d1d5cba..000000000000 --- a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/expressions.ql +++ /dev/null @@ -1,13 +0,0 @@ -class Expression extends @expr { - string toString() { none() } -} - -class TypeOrRef extends @type_or_ref { - string toString() { none() } -} - -from Expression e, int k, int kind, TypeOrRef t -where - expressions(e, k, t) and - if k = 138 then kind = 106 else kind = k -select e, kind, t diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/string_interpol_insert.ql b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/string_interpol_insert.ql new file mode 100644 index 000000000000..3f83b1ea3cce --- /dev/null +++ b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/string_interpol_insert.ql @@ -0,0 +1,39 @@ +class Expr extends @expr { + string toString() { none() } +} + +class TypeOrRef extends @type_or_ref { + string toString() { none() } +} + +class InterpolatedStringInsertExpr extends Expr, @interpolated_string_insert_expr { } + +private predicate remove_expr(Expr e) { + exists(InterpolatedStringInsertExpr ie | + e = ie + or + // Alignment + expr_parent(e, 1, ie) + or + // Format + expr_parent(e, 2, ie) + ) +} + +query predicate new_expressions(Expr e, int kind, TypeOrRef t) { + expressions(e, kind, t) and + // Remove the syntheetic intert expression and previously un-extracted children + not remove_expr(e) +} + +query predicate new_expr_parent(Expr e, int child, Expr parent) { + expr_parent(e, child, parent) and + not remove_expr(e) and + not remove_expr(parent) + or + // Use the string interpolation as parent instead of the synthetic insert expression + exists(InterpolatedStringInsertExpr ie | + expr_parent(e, 0, ie) and + expr_parent(ie, child, parent) + ) +} diff --git a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties index 9e9a659b10a3..9e8118060f2b 100644 --- a/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties +++ b/csharp/downgrades/66044cfa5bbf2ecfabd06ead25e91db2bdd79764/upgrade.properties @@ -1,3 +1,4 @@ description: Remove `interpolated_string_insert_expr` kind. -compatibility: partial -expressions.rel: run expressions.qlo +compatibility: backwards +expressions.rel: run string_interpol_insert.qlo new_expressions +expr_parent.rel: run string_interpol_insert.qlo new_expr_parent