From 0e12df0a151471292c9057afdea51192b796b50a Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 4 Jun 2019 16:02:32 +0200 Subject: [PATCH 01/20] Java: Add SwitchExpr support in Guards.qll --- java/ql/src/semmle/code/java/Statement.qll | 13 ++++++++++++- .../src/semmle/code/java/controlflow/Guards.qll | 16 +++++++++------- java/ql/test/library-tests/guards12/Test.java | 9 +++++++++ .../test/library-tests/guards12/guard.expected | 1 + java/ql/test/library-tests/guards12/guard.ql | 8 ++++++++ java/ql/test/library-tests/guards12/options | 1 + 6 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 java/ql/test/library-tests/guards12/Test.java create mode 100644 java/ql/test/library-tests/guards12/guard.expected create mode 100644 java/ql/test/library-tests/guards12/guard.ql create mode 100644 java/ql/test/library-tests/guards12/options diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index e3e3f3e7976..2dfa5d26456 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -423,6 +423,14 @@ class SwitchCase extends Stmt, @case { */ SwitchExpr getSwitchExpr() { result.getACase() = this } + /** + * Gets the expression of the surrounding switch that this case is compared + * against. + */ + Expr getTestExpr() { + result = this.getSwitch().getExpr() or result = this.getSwitchExpr().getExpr() + } + /** * PREVIEW FEATURE in Java 12. Subject to removal in a future release. * @@ -625,7 +633,10 @@ class BreakStmt extends Stmt, @breakstmt { override string pp() { if this.hasLabel() then result = "break " + this.getLabel() - else if this.hasValue() then result = "break ..." else result = "break" + else + if this.hasValue() + then result = "break ..." + else result = "break" } /** This statement's Halstead ID (used to compute Halstead metrics). */ diff --git a/java/ql/src/semmle/code/java/controlflow/Guards.qll b/java/ql/src/semmle/code/java/controlflow/Guards.qll index de05b121433..976f90c17b1 100644 --- a/java/ql/src/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/src/semmle/code/java/controlflow/Guards.qll @@ -93,7 +93,8 @@ class Guard extends ExprParent { /** Gets the statement containing this guard. */ Stmt getEnclosingStmt() { result = this.(Expr).getEnclosingStmt() or - result = this.(SwitchCase).getSwitch() + result = this.(SwitchCase).getSwitch() or + result = this.(SwitchCase).getSwitchExpr().getEnclosingStmt() } /** @@ -126,7 +127,7 @@ class Guard extends ExprParent { branch = true and bb2.getFirstNode() = sc.getControlFlowNode() and pred = sc.getControlFlowNode().getAPredecessor() and - pred.(Expr).getParent*() = sc.getSwitch().getExpr() and + pred.(Expr).getParent*() = sc.getTestExpr() and bb1 = pred.getBasicBlock() ) or @@ -160,12 +161,12 @@ class Guard extends ExprParent { } private predicate switchCaseControls(SwitchCase sc, BasicBlock bb) { - exists(BasicBlock caseblock, SwitchStmt ss | - ss.getACase() = sc and + exists(BasicBlock caseblock, Expr switchTest | + switchTest = sc.getTestExpr() and caseblock.getFirstNode() = sc.getControlFlowNode() and caseblock.bbDominates(bb) and forall(ControlFlowNode pred | pred = sc.getControlFlowNode().getAPredecessor() | - pred.(Expr).getParent*() = ss.getExpr() + pred.(Expr).getParent*() = switchTest ) ) } @@ -254,7 +255,8 @@ private predicate equalityGuard(Guard g, Expr e1, Expr e2, boolean polarity) { exists(ConstCase cc | cc = g and polarity = true and - cc.getSwitch().getExpr().getProperExpr() = e1 and - cc.getValue() = e2 + cc.getTestExpr().getProperExpr() = e1 and + cc.getValue() = e2 and + strictcount(cc.getValue(_)) = 1 ) } diff --git a/java/ql/test/library-tests/guards12/Test.java b/java/ql/test/library-tests/guards12/Test.java new file mode 100644 index 00000000000..03ccc92d245 --- /dev/null +++ b/java/ql/test/library-tests/guards12/Test.java @@ -0,0 +1,9 @@ +class Test { + void foo(String s) { + int x = switch(s) { + case "a", "b" -> 1; + case "c" -> 2; + default -> 3; + }; + } +} diff --git a/java/ql/test/library-tests/guards12/guard.expected b/java/ql/test/library-tests/guards12/guard.expected new file mode 100644 index 00000000000..d578ba1141d --- /dev/null +++ b/java/ql/test/library-tests/guards12/guard.expected @@ -0,0 +1 @@ +| Test.java:5:7:5:17 | stmt | Test.java:3:20:3:20 | s | Test.java:5:12:5:14 | "c" | true | true | Test.java:5:7:5:17 | stmt | diff --git a/java/ql/test/library-tests/guards12/guard.ql b/java/ql/test/library-tests/guards12/guard.ql new file mode 100644 index 00000000000..206e85f8bb8 --- /dev/null +++ b/java/ql/test/library-tests/guards12/guard.ql @@ -0,0 +1,8 @@ +import java +import semmle.code.java.controlflow.Guards + +from Guard g, BasicBlock bb, boolean branch, VarAccess e1, Expr e2, boolean pol +where + g.controls(bb, branch) and + g.isEquality(e1, e2, pol) +select g, e1, e2, pol, branch, bb diff --git a/java/ql/test/library-tests/guards12/options b/java/ql/test/library-tests/guards12/options new file mode 100644 index 00000000000..33d712034f9 --- /dev/null +++ b/java/ql/test/library-tests/guards12/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 12 -target 12 From c09b859aa7953eb85ce6a41b1db64cf314bffc5f Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 4 Jun 2019 17:17:14 +0100 Subject: [PATCH 02/20] JavaScript: Add three missing `@metricType` annotations. --- javascript/ql/src/filters/FilterFrameworksForMetric.ql | 1 + javascript/ql/src/filters/FilterGeneratedForMetric.ql | 1 + javascript/ql/src/filters/FilterMinifiedForMetric.ql | 1 + 3 files changed, 3 insertions(+) diff --git a/javascript/ql/src/filters/FilterFrameworksForMetric.ql b/javascript/ql/src/filters/FilterFrameworksForMetric.ql index 72916a26351..5c65e055614 100644 --- a/javascript/ql/src/filters/FilterFrameworksForMetric.ql +++ b/javascript/ql/src/filters/FilterFrameworksForMetric.ql @@ -3,6 +3,7 @@ * @description Only keep results in non-framework code * @kind treemap * @id js/not-framework-file-metric-filter + * @metricType file */ import FilterFrameworks diff --git a/javascript/ql/src/filters/FilterGeneratedForMetric.ql b/javascript/ql/src/filters/FilterGeneratedForMetric.ql index 89ba33dcda8..71f5026de39 100644 --- a/javascript/ql/src/filters/FilterGeneratedForMetric.ql +++ b/javascript/ql/src/filters/FilterGeneratedForMetric.ql @@ -5,6 +5,7 @@ * mapping comment. * @kind treemap * @id js/not-generated-file-metric-filter + * @metricType file */ import semmle.javascript.GeneratedCode diff --git a/javascript/ql/src/filters/FilterMinifiedForMetric.ql b/javascript/ql/src/filters/FilterMinifiedForMetric.ql index e209fb0ee3e..002e0b86c54 100644 --- a/javascript/ql/src/filters/FilterMinifiedForMetric.ql +++ b/javascript/ql/src/filters/FilterMinifiedForMetric.ql @@ -3,6 +3,7 @@ * @description Only keep results from files that are not minified. * @kind treemap * @id js/not-minified-file-metric-filter + * @metricType file */ import javascript From 599a5b1eef0f11aab42e8f811d4fdbc9f8cb4f9b Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 May 2019 11:12:45 +0100 Subject: [PATCH 03/20] C#: Make @local_function @modifiable, make LocalFunction extend Modifiable, and extract modifiers for local functions. --- .../Entities/LocalFunction.cs | 14 ++++++++++++++ csharp/ql/src/semmle/code/csharp/Callable.qll | 2 +- .../library-tests/csharp8/StaticLocalFunctions.cs | 13 +++++++++++++ .../csharp8/StaticLocalFunctions.expected | 1 + .../library-tests/csharp8/StaticLocalFunctions.ql | 5 +++++ 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs create mode 100644 csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected create mode 100644 csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 7d808e0fd3a..e209b73f78d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -1,4 +1,6 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; namespace Semmle.Extraction.CSharp.Entities { @@ -39,6 +41,18 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate() { PopulateMethod(); + + // There is a "bug" in Roslyn whereby the IMethodSymbol associated with the local function symbol + // is always static, so we need to go to the syntax reference of the local function to see whether + // the "static" modifier is present. + if (symbol.DeclaringSyntaxReferences.SingleOrDefault().GetSyntax() is LocalFunctionStatementSyntax fn) + { + foreach(var modifier in fn.Modifiers) + { + Modifier.HasModifier(Context, this, modifier.Text); + } + } + var originalDefinition = IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition); var returnType = Type.Create(Context, symbol.ReturnType); Context.Emit(Tuples.local_functions(this, symbol.Name, returnType, originalDefinition)); diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 6920d917aa4..22b46d89b96 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -903,7 +903,7 @@ class ExplicitConversionOperator extends ConversionOperator { * } * ``` */ -class LocalFunction extends Callable, @local_function { +class LocalFunction extends Callable, Modifiable, @local_function { override string getName() { local_functions(this, result, _, _) } override LocalFunction getSourceDeclaration() { local_functions(this, _, _, result) } diff --git a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs new file mode 100644 index 00000000000..3074565fc47 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.cs @@ -0,0 +1,13 @@ +// semmle-extractor-options: /langversion:8.0 + +using System; + +class StaticLocalFunctions +{ + int Fn(int x) + { + static int I(int y) => y; + int J(int y) => x+y; + return I(x) + J(x); + } +} diff --git a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected new file mode 100644 index 00000000000..1cf511ba8f9 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.expected @@ -0,0 +1 @@ +| StaticLocalFunctions.cs:9:9:9:33 | I | static | diff --git a/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.ql b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.ql new file mode 100644 index 00000000000..51fff4fc9f7 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/StaticLocalFunctions.ql @@ -0,0 +1,5 @@ +import csharp + +from LocalFunction fn, string modifier +where fn.hasModifier(modifier) +select fn, modifier \ No newline at end of file From ac3a06f77b18ec49288e5b8753239c91e770f716 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 May 2019 11:59:01 +0100 Subject: [PATCH 04/20] C#: Implement null coalescing assignment operator --- .../Entities/Expressions/Assignment.cs | 4 ++++ .../Entities/Expressions/Factory.cs | 1 + .../Semmle.Extraction.CSharp/Kinds/ExprKind.cs | 3 ++- csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll | 7 +++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 5 +++-- .../library-tests/csharp8/NullCoalescingAssignment.cs | 10 ++++++++++ .../csharp8/NullCoalescingAssignment.expected | 4 ++++ .../library-tests/csharp8/NullCoalescingAssignment.ql | 7 +++++++ .../csharp8/NullCoalescingControlFlow.expected | 11 +++++++++++ .../csharp8/NullCoalescingControlFlow.ql | 10 ++++++++++ 10 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.cs create mode 100644 csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected create mode 100644 csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.ql create mode 100644 csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.expected create mode 100644 csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs index 921787cabc5..be903d2ec55 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs @@ -71,6 +71,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.ASSIGN_LSHIFT; case SyntaxKind.GreaterThanGreaterThanEqualsToken: return ExprKind.ASSIGN_RSHIFT; + case SyntaxKind.QuestionQuestionEqualsToken: + return ExprKind.ASSIGN_COALESCE; default: cx.ModelError(syntax, "Unrecognised assignment type " + GetKind(cx, syntax)); return ExprKind.UNKNOWN; @@ -142,6 +144,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.SUB; case ExprKind.ASSIGN_XOR: return ExprKind.BIT_XOR; + case ExprKind.ASSIGN_COALESCE: + return ExprKind.NULL_COALESCING; default: cx.ModelError(Syntax, "Couldn't unfold assignment of type " + kind); return ExprKind.UNKNOWN; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs index 21cd02ec058..37ad90d7e5c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs @@ -80,6 +80,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case SyntaxKind.RightShiftAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: + case SyntaxKind.CoalesceAssignmentExpression: return Assignment.Create(info); case SyntaxKind.ObjectCreationExpression: diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs index c81496ef519..f036274e1bd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs @@ -112,6 +112,7 @@ namespace Semmle.Extraction.Kinds RECURSIVE_PATTERN = 115, PROPERTY_PATTERN = 116, POSITIONAL_PATTERN = 117, - SWITCH_CASE = 118 + SWITCH_CASE = 118, + ASSIGN_COALESCE = 119 } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll index 0473a0820ff..fe1a131e46c 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll @@ -230,3 +230,10 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr { class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr { override string toString() { result = "... -= ..." } } + +/** + * A null-coalescing assignment operation, for example `x ??= y`. + */ +class AssignCoalesceExpr extends AssignOperation, @assign_coalesce_expr { + override string toString() { result = "... ??= ..." } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 22d4df34563..c6a1c556b9b 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -526,7 +526,7 @@ specific_type_parameter_constraints( @modifiable = @modifiable_direct | @event_accessor; -@modifiable_direct = @member | @accessor; +@modifiable_direct = @member | @accessor | @local_function; modifiers( unique int id: @modifier, @@ -983,6 +983,7 @@ case @expr.kind of | 116 = @property_pattern_expr | 117 = @positional_pattern_expr | 118 = @switch_case_expr +| 119 = @assign_coalesce_expr ; @switch = @switch_stmt | @switch_expr; @@ -995,7 +996,7 @@ case @expr.kind of | @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_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 diff --git a/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.cs b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.cs new file mode 100644 index 00000000000..41e6e5b4c8a --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.cs @@ -0,0 +1,10 @@ +using System; + +class NullCoalescingAssignment +{ + void NullCoalescing() + { + object o = null; + o ??= this; + } +} diff --git a/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected new file mode 100644 index 00000000000..77ace0339a9 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected @@ -0,0 +1,4 @@ +nullcoalescing +| NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | +assignments +| NullCoalescingAssignment.cs:8:9:8:18 | ... ??= ... | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | diff --git a/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.ql b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.ql new file mode 100644 index 00000000000..a3a8ca20e92 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.ql @@ -0,0 +1,7 @@ +import csharp + +query predicate nullcoalescing(NullCoalescingExpr expr) { any() } + +query predicate assignments(AssignCoalesceExpr expr, Expr expanded) { + expanded = expr.getExpandedAssignment() +} diff --git a/csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.expected b/csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.expected new file mode 100644 index 00000000000..9c16747aefa --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.expected @@ -0,0 +1,11 @@ +| NullCoalescingAssignment.cs:5:10:5:23 | enter NullCoalescing | NullCoalescingAssignment.cs:6:5:9:5 | {...} | semmle.label | successor | +| NullCoalescingAssignment.cs:6:5:9:5 | {...} | NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | semmle.label | successor | +| NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | NullCoalescingAssignment.cs:7:20:7:23 | null | semmle.label | successor | +| NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | NullCoalescingAssignment.cs:8:9:8:19 | ...; | semmle.label | successor | +| NullCoalescingAssignment.cs:7:20:7:23 | null | NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | semmle.label | successor | +| NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | semmle.label | non-null | +| NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | NullCoalescingAssignment.cs:8:15:8:18 | this access | semmle.label | null | +| NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | NullCoalescingAssignment.cs:5:10:5:23 | exit NullCoalescing | semmle.label | successor | +| NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | semmle.label | successor | +| NullCoalescingAssignment.cs:8:9:8:19 | ...; | NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | semmle.label | successor | +| NullCoalescingAssignment.cs:8:15:8:18 | this access | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.ql b/csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.ql new file mode 100644 index 00000000000..e509bdfd70f --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/NullCoalescingControlFlow.ql @@ -0,0 +1,10 @@ +import csharp +import semmle.code.csharp.controlflow.ControlFlowGraph + +query predicate edges(ControlFlow::Node node1, ControlFlow::Node node2, string label, string value) { + label = "semmle.label" and + exists(ControlFlow::SuccessorType t | + node2 = node1.getASuccessorByType(t) and value = t.toString() + ) + and node1.getEnclosingCallable().hasName("NullCoalescing") +} From 15cd1d274af6059916e682d49498d682fc5e7920 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 May 2019 17:09:57 +0100 Subject: [PATCH 05/20] C#: Implement using declaration statements. --- .../Entities/Statements/LocalDeclaration.cs | 12 +++++++++++- .../Semmle.Extraction.CSharp/Kinds/StmtKind.cs | 3 ++- csharp/ql/src/semmle/code/csharp/Stmt.qll | 11 +++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs index 671b4d7d99e..9a53c4c8f57 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs @@ -1,3 +1,4 @@ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; using Semmle.Extraction.Kinds; @@ -6,8 +7,17 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { class LocalDeclaration : Statement { + static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt) + { + if (declStmt.UsingKeyword.RawKind != 0) return StmtKind.USING_DECL; + + if (declStmt.IsConst) return StmtKind.CONST_DECL; + + return StmtKind.VAR_DECL; + } + LocalDeclaration(Context cx, LocalDeclarationStatementSyntax declStmt, IStatementParentEntity parent, int child) - : base(cx, declStmt, declStmt.IsConst ? StmtKind.CONST_DECL : StmtKind.VAR_DECL, parent, child) { } + : base(cx, declStmt, GetKind(declStmt), parent, child) { } public static LocalDeclaration Create(Context cx, LocalDeclarationStatementSyntax node, IStatementParentEntity parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/StmtKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/StmtKind.cs index f55ab664794..4248e65be09 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/StmtKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/StmtKind.cs @@ -34,6 +34,7 @@ namespace Semmle.Extraction.Kinds // lgtm[cs/similar-file] LABEL = 27, CATCH = 28, CASE = 29, - LOCAL_FUNCTION = 30 + LOCAL_FUNCTION = 30, + USING_DECL = 31 } } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 936edaf58c4..fcfdf86efdf 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1254,6 +1254,17 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { override string toString() { result = "const ... ...;" } } +/** + * A `using` declaration statement, for example + * + * ``` + * using FileStream f = File.Open("settings.xml"); + * ``` + */ +class UsingDeclStmt extends LocalVariableDeclStmt, @using_decl_stmt { + override string toString() { result = "using ... ...;" } +} + /** * An empty statement, for example line 2 in * diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index c6a1c556b9b..d722207ad10 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -808,11 +808,12 @@ case @stmt.kind of | 28 = @catch | 29 = @case_stmt | 30 = @local_function_stmt +| 31 = @using_decl_stmt ; @labeled_stmt = @label_stmt | @case; -@decl_stmt = @var_decl_stmt | @const_decl_stmt; +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; @cond_stmt = @if_stmt | @switch_stmt; From 923fbe4c9e98af23d5846a6957cf4373aff73ad8 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 24 May 2019 10:45:54 +0100 Subject: [PATCH 06/20] C#: Implement QL model for `using` declarations, introducing `UsingBlockStmt` and a `UsingDeclStmt`. --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 54 ++++++++++++++++--- .../csharp/controlflow/ControlFlowGraph.qll | 2 +- csharp/ql/src/semmlecode.csharp.dbscheme | 4 +- .../csharp8/UsingDeclarations.cs | 17 ++++++ .../csharp8/UsingDeclarations.expected | 18 +++++++ .../csharp8/UsingDeclarations.ql | 17 ++++++ .../test/library-tests/statements/Using1.ql | 2 +- 7 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 csharp/ql/test/library-tests/csharp8/UsingDeclarations.cs create mode 100644 csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected create mode 100644 csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index fcfdf86efdf..945ecf648b1 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1115,7 +1115,39 @@ class LockStmt extends Stmt, @lock_stmt { } /** - * A `using` statement, for example + * A using block or declaration. Either a using declaration (`UsingDecStmt`) or + * a using block (`UsingBlockStmt`). + */ +class UsingStmt extends Stmt, @using_stmt { + /** Gets the `i`th local variable declaration of this `using` statement. */ + LocalVariableDeclExpr getVariableDeclExpr(int i) { none() } + + /** Gets a local variable declaration of this `using` statement. */ + LocalVariableDeclExpr getAVariableDeclExpr() { none() } + + /** + * DEPRECATED: Use UsingBlockStmt.getExpr() instead. + * Gets the expression directly used by this `using` statement, if any. For + * example, `f` on line 2 in + * + * ``` + * var f = File.Open("settings.xml"); + * using (f) { + * ... + * } + * ``` + */ + deprecated Expr getExpr() { none() } + + /** + * DEPRECATED: Use UsingBlockStmt.getBody() instead. + * Gets the body of this `using` statement. + */ + deprecated Stmt getBody() { none() } +} + +/** + * A `using` block statement, for example * * ``` * using (FileStream f = File.Open("settings.xml")) { @@ -1123,7 +1155,7 @@ class LockStmt extends Stmt, @lock_stmt { * } * ``` */ -class UsingStmt extends Stmt, @using_stmt { +class UsingBlockStmt extends UsingStmt, @using_block_stmt { /** Gets the `i`th local variable of this `using` statement. */ LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() } @@ -1131,10 +1163,10 @@ class UsingStmt extends Stmt, @using_stmt { LocalVariable getAVariable() { result = this.getVariable(_) } /** Gets the `i`th local variable declaration of this `using` statement. */ - LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) } + override LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) } /** Gets a local variable declaration of this `using` statement. */ - LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } + override LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } /** * Gets the expression directly used by this `using` statement, if any. For @@ -1147,7 +1179,7 @@ class UsingStmt extends Stmt, @using_stmt { * } * ``` */ - Expr getExpr() { result = this.getChild(0) } + override Expr getExpr() { result = this.getChild(0) } /** * Gets an expression that is used in this `using` statement. Either an @@ -1176,7 +1208,7 @@ class UsingStmt extends Stmt, @using_stmt { } /** Gets the body of this `using` statement. */ - Stmt getBody() { result.getParent() = this } + override Stmt getBody() { result.getParent() = this } override string toString() { result = "using (...) {...}" } } @@ -1261,8 +1293,16 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { * using FileStream f = File.Open("settings.xml"); * ``` */ -class UsingDeclStmt extends LocalVariableDeclStmt, @using_decl_stmt { +class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { override string toString() { result = "using ... ...;" } + + override LocalConstantDeclExpr getAVariableDeclExpr() { + result = LocalVariableDeclStmt.super.getAVariableDeclExpr() + } + + override LocalConstantDeclExpr getVariableDeclExpr(int n) { + result = LocalVariableDeclStmt.super.getVariableDeclExpr(n) + } } /** diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index db429876d48..2618fd4bc63 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -480,7 +480,7 @@ module ControlFlow { i = max(int j | exists(fs.getVariableDeclExpr(j))) + 1 ) or - this = any(UsingStmt us | + this = any(UsingBlockStmt us | if exists(us.getExpr()) then ( result = us.getExpr() and diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index d722207ad10..027e958f156 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -798,7 +798,7 @@ case @stmt.kind of | 18 = @checked_stmt | 19 = @unchecked_stmt | 20 = @lock_stmt -| 21 = @using_stmt +| 21 = @using_block_stmt | 22 = @var_decl_stmt | 23 = @const_decl_stmt | 24 = @empty_stmt @@ -811,6 +811,8 @@ case @stmt.kind of | 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; diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.cs b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.cs new file mode 100644 index 00000000000..95806d5da83 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; + +class UsingDeclarations +{ + void TestUsingDeclarations() + { + using FileStream file1 = new FileStream("...", FileMode.Open), file2 = new FileStream("...", FileMode.Open); + + using(FileStream file3 = new FileStream("...", FileMode.Open), file4 = new FileStream("...", FileMode.Open)) + { + } + + using(new FileStream("...", FileMode.Open)) + ; + } +} diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected new file mode 100644 index 00000000000..fd37ac0e746 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected @@ -0,0 +1,18 @@ +localVars +| NullCoalescingAssignment.cs:7:16:7:16 | o | +| UsingDeclarations.cs:8:26:8:30 | file1 | +| UsingDeclarations.cs:8:72:8:76 | file2 | +| UsingDeclarations.cs:10:26:10:30 | file3 | +| UsingDeclarations.cs:10:72:10:76 | file4 | +localVariableDeclarations +| NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | 0 | NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | +usingStmts1 +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | +| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | +| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | +usingStmts +| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 0 | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | +| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 1 | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | +usingDecls +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql new file mode 100644 index 00000000000..e6c6acb5dd9 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql @@ -0,0 +1,17 @@ +import csharp + +query predicate localVars(LocalVariable decl) { any() } + +query predicate localVariableDeclarations( + LocalVariableDeclStmt stmt, int i, LocalVariableDeclExpr decl +) { + decl = stmt.getVariableDeclExpr(i) +} + +query predicate usingStmts1(UsingStmt stmt) { any() } + +query predicate usingStmts(UsingStmt stmt, int i, LocalVariableDeclExpr decl) { + decl = stmt.getVariableDeclExpr(i) +} + +query predicate usingDecls(UsingDeclStmt stmt, int i, Expr e) { e = stmt.getChild(i) } diff --git a/csharp/ql/test/library-tests/statements/Using1.ql b/csharp/ql/test/library-tests/statements/Using1.ql index 7274aa4a0e0..6afe7a3c7d4 100644 --- a/csharp/ql/test/library-tests/statements/Using1.ql +++ b/csharp/ql/test/library-tests/statements/Using1.ql @@ -5,7 +5,7 @@ import csharp where - forall(UsingStmt s | + forall(UsingBlockStmt s | exists(s.getAnExpr()) and exists(s.getBody()) ) From fa89d2b845a5a140011b797353541e3627813124 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 24 May 2019 16:45:58 +0100 Subject: [PATCH 07/20] C#: Update stats and test output. --- csharp/ql/src/semmlecode.csharp.dbscheme.stats | 10 +++++++++- .../library-tests/csharp8/UsingDeclarations.expected | 2 -- .../ql/test/library-tests/csharp8/UsingDeclarations.ql | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index dcbb2ba7ca5..5223cf105a2 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -360,10 +360,14 @@ 1854 -@using_stmt +@using_block_stmt 5815 +@using_decl_stmt +1000 + + @var_decl_stmt 243866 @@ -688,6 +692,10 @@ 116 +@assign_coalesce_expr +116 + + @object_init_expr 5320 diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected index fd37ac0e746..53bd4f957d9 100644 --- a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected @@ -1,11 +1,9 @@ localVars -| NullCoalescingAssignment.cs:7:16:7:16 | o | | UsingDeclarations.cs:8:26:8:30 | file1 | | UsingDeclarations.cs:8:72:8:76 | file2 | | UsingDeclarations.cs:10:26:10:30 | file3 | | UsingDeclarations.cs:10:72:10:76 | file4 | localVariableDeclarations -| NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | 0 | NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | usingStmts1 | UsingDeclarations.cs:8:9:8:116 | using ... ...; | | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql index e6c6acb5dd9..3e0d16e1ca8 100644 --- a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql @@ -1,10 +1,13 @@ import csharp -query predicate localVars(LocalVariable decl) { any() } +query predicate localVars(LocalVariable decl) { + decl.getEnclosingCallable().hasName("TestUsingDeclarations") +} query predicate localVariableDeclarations( LocalVariableDeclStmt stmt, int i, LocalVariableDeclExpr decl ) { + decl.getEnclosingCallable().hasName("TestUsingDeclarations") and decl = stmt.getVariableDeclExpr(i) } From d6fac7bfb7e65d73f1597b764e3c285419d56dcc Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 3 Jun 2019 12:17:15 +0100 Subject: [PATCH 08/20] C#: Delete file. --- .../test/library-tests/csharp8/StaticLocalFunction.cs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 csharp/ql/test/library-tests/csharp8/StaticLocalFunction.cs diff --git a/csharp/ql/test/library-tests/csharp8/StaticLocalFunction.cs b/csharp/ql/test/library-tests/csharp8/StaticLocalFunction.cs deleted file mode 100644 index 8b530074227..00000000000 --- a/csharp/ql/test/library-tests/csharp8/StaticLocalFunction.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -class StaticLocalFunction -{ - int F() - { - static int G(int x) => x; - return G(12); - } -} From 5679a72f37e0cc9489a0b7a3c5cca6aff92b43b7 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 3 Jun 2019 12:18:45 +0100 Subject: [PATCH 09/20] C#: DB Upgrade script --- .../old.dbscheme | 1872 ++++++++++++++++ .../semmlecode.csharp.dbscheme | 1876 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 3750 insertions(+) create mode 100644 csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/old.dbscheme create mode 100644 csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/semmlecode.csharp.dbscheme create mode 100644 csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties diff --git a/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/old.dbscheme b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/old.dbscheme new file mode 100644 index 00000000000..22d4df34563 --- /dev/null +++ b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/old.dbscheme @@ -0,0 +1,1872 @@ + +/** + * 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 +); + +/** + * 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 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_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_default 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_default 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 +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + varchar(900) queryPath: string ref, + int location: @location ref, + varchar(900) message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + varchar(900) queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + varchar(900) path: string ref, + int column: int ref, + varchar(900) value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + varchar(900) prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * Version history + */ + +svnentries( + int id: @svnentry, + varchar(500) revision: string ref, + varchar(500) author: string ref, + date revisionDate: date ref, + int changeSize: int ref); + +svnaffectedfiles( + int id: @svnentry ref, + int file: @file ref, + varchar(500) action: string ref); + +svnentrymsg( + int id: @svnentry ref, + varchar(500) message: string ref +) + +svnchurn( + int commit: @svnentry ref, + int file: @file ref, + int addedLines: int ref, + int deletedLines: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** 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); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + unique 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, + varchar(900) fullname: string ref, + varchar(900) name: string ref, + varchar(900) version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: 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, + varchar(900) 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_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); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + varchar(900) 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 + ; + +@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; +@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, + varchar(900) name: string ref); + +typeref_type( + unique 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); + +extend( + unique int sub: @type ref, + int super: @type_or_ref 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: @struct_type 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 type_id: @type_or_ref ref, + int target: @attributable ref); + +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); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +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); + + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor; + +modifiers( + unique int id: @modifier, + varchar(900) name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + varchar(900) 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, + varchar(900) 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, + varchar(900) 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, + varchar(900) name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + varchar(900) 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, + varchar(900) 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, + varchar(900) name: string ref, + varchar(900) 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( + unique int id: @variable ref, + varchar(900) 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, + varchar(900) 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, + varchar(900) 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, + varchar(900) 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( + unique int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + varchar(900) 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); + +@ref_callable = @local_function | @method | @delegate_type; + +ref_returns(int fn: @ref_callable ref); + +ref_readonly_returns(int fn: @ref_callable ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + varchar(900) 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, + varchar(900) 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; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + varchar(900) name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** 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_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 + ; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_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 */); + +/** 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; + +@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 = @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 +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_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; +@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_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; + +@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; +@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; +@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; + +@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_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + varchar(900) 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; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + varchar(900) 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, + varchar(900) name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + varchar(900) encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) 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, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) 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, + varchar(800) text: string ref, + varchar(800) 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, + varchar(1000) name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + varchar(1000) name: string ref); +asp_element_body( + unique int element: @asp_element ref, + varchar(1000) body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + varchar(1000) name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + varchar(1000) name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + varchar(900) value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + varchar(900) name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + varchar(900) name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + varchar(900) name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + varchar(900) name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + varchar(900) name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + varchar(100) param: string ref, + varchar(900) value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + varchar(900) value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/semmlecode.csharp.dbscheme b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..027e958f156 --- /dev/null +++ b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/semmlecode.csharp.dbscheme @@ -0,0 +1,1876 @@ + +/** + * 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 +); + +/** + * 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 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_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_default 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_default 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 +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + varchar(900) queryPath: string ref, + int location: @location ref, + varchar(900) message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + varchar(900) queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + varchar(900) path: string ref, + int column: int ref, + varchar(900) value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + varchar(900) prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * Version history + */ + +svnentries( + int id: @svnentry, + varchar(500) revision: string ref, + varchar(500) author: string ref, + date revisionDate: date ref, + int changeSize: int ref); + +svnaffectedfiles( + int id: @svnentry ref, + int file: @file ref, + varchar(500) action: string ref); + +svnentrymsg( + int id: @svnentry ref, + varchar(500) message: string ref +) + +svnchurn( + int commit: @svnentry ref, + int file: @file ref, + int addedLines: int ref, + int deletedLines: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** 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); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + unique 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, + varchar(900) fullname: string ref, + varchar(900) name: string ref, + varchar(900) version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: 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, + varchar(900) 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_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); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + varchar(900) 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 + ; + +@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; +@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, + varchar(900) name: string ref); + +typeref_type( + unique 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); + +extend( + unique int sub: @type ref, + int super: @type_or_ref 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: @struct_type 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 type_id: @type_or_ref ref, + int target: @attributable ref); + +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); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +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); + + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + varchar(900) name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + varchar(900) 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, + varchar(900) 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, + varchar(900) 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, + varchar(900) name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + varchar(900) 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, + varchar(900) 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, + varchar(900) name: string ref, + varchar(900) 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( + unique int id: @variable ref, + varchar(900) 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, + varchar(900) 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, + varchar(900) 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, + varchar(900) 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( + unique int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + varchar(900) 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); + +@ref_callable = @local_function | @method | @delegate_type; + +ref_returns(int fn: @ref_callable ref); + +ref_readonly_returns(int fn: @ref_callable ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + varchar(900) 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, + varchar(900) 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; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + varchar(900) name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** 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 */); + +/** 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; + +@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 = @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 +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_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; +@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; + +@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; +@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; +@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; + +@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_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + varchar(900) 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; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + varchar(900) 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, + varchar(900) name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + varchar(900) encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) 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, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) 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, + varchar(800) text: string ref, + varchar(800) 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, + varchar(1000) name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + varchar(1000) name: string ref); +asp_element_body( + unique int element: @asp_element ref, + varchar(1000) body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + varchar(1000) name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + varchar(1000) name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + varchar(900) value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + varchar(900) name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + varchar(900) name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + varchar(900) name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + varchar(900) name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + varchar(900) name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + varchar(100) param: string ref, + varchar(900) value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + varchar(900) value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties new file mode 100644 index 00000000000..02a033c3472 --- /dev/null +++ b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties @@ -0,0 +1,2 @@ +description: Support for null-coalescing assignment, static local functions and using declarations. +compatibility: backwards From 73c2898666a4e59d5d0bc74b838cbccebca59d38 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 3 Jun 2019 14:47:15 +0100 Subject: [PATCH 10/20] C#: Minor edits. --- .../Entities/Statements/LocalDeclaration.cs | 7 ++++--- csharp/ql/src/semmle/code/csharp/Stmt.qll | 7 ++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs index 9a53c4c8f57..51f62038c26 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs @@ -1,4 +1,3 @@ -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; using Semmle.Extraction.Kinds; @@ -9,9 +8,11 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt) { - if (declStmt.UsingKeyword.RawKind != 0) return StmtKind.USING_DECL; + if (declStmt.UsingKeyword.RawKind != 0) + return StmtKind.USING_DECL; - if (declStmt.IsConst) return StmtKind.CONST_DECL; + if (declStmt.IsConst) + return StmtKind.CONST_DECL; return StmtKind.VAR_DECL; } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 945ecf648b1..863a08040b7 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1115,7 +1115,7 @@ class LockStmt extends Stmt, @lock_stmt { } /** - * A using block or declaration. Either a using declaration (`UsingDecStmt`) or + * A using block or declaration. Either a using declaration (`UsingDeclStmt`) or * a using block (`UsingBlockStmt`). */ class UsingStmt extends Stmt, @using_stmt { @@ -1123,7 +1123,7 @@ class UsingStmt extends Stmt, @using_stmt { LocalVariableDeclExpr getVariableDeclExpr(int i) { none() } /** Gets a local variable declaration of this `using` statement. */ - LocalVariableDeclExpr getAVariableDeclExpr() { none() } + LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } /** * DEPRECATED: Use UsingBlockStmt.getExpr() instead. @@ -1165,9 +1165,6 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { /** Gets the `i`th local variable declaration of this `using` statement. */ override LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) } - /** Gets a local variable declaration of this `using` statement. */ - override LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } - /** * Gets the expression directly used by this `using` statement, if any. For * example, `f` on line 2 in From 4b3297ceef534246ca000e9e6d152d8f8988e556 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 3 Jun 2019 14:58:55 +0100 Subject: [PATCH 11/20] C#: Analysis change notes --- change-notes/1.21/analysis-csharp.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/change-notes/1.21/analysis-csharp.md b/change-notes/1.21/analysis-csharp.md index 90bd402fc21..d38316872ac 100644 --- a/change-notes/1.21/analysis-csharp.md +++ b/change-notes/1.21/analysis-csharp.md @@ -13,6 +13,10 @@ * The following C# 8 features are now extracted: - Range expressions - Recursive patterns + - Using declaration statements + - `static` modifiers on local functions + - Null-coalescing assignment expressions + * The `unmanaged` type parameter constraint is now extracted. ## Changes to QL libraries @@ -20,6 +24,7 @@ * The class `Attribute` has two new predicates: `getConstructorArgument()` and `getNamedArgument()`. The first predicate returns arguments to the underlying constructor call and the latter returns named arguments for initializing fields and properties. * The class `TypeParameterConstraints` has a new predicate `hasUnmanagedTypeConstraint()`, indicating that the type parameter has the `unmanaged` constraint. * The following QL classes have been added to model C# 8 features: + - Class `AssignCoalesceExpr` models null-coalescing assignment, for example `x ??= y` - Class `IndexExpr` models from-end index expressions, for example `^1` - Class `PatternExpr` is an `Expr` that appears in a pattern. It has the new subclasses `DiscardPatternExpr`, `LabeledPatternExpr`, `RecursivePatternExpr`, `TypeAccessPatternExpr`, `TypePatternExpr`, and `VariablePatternExpr`. - Class `PatternMatch` models a pattern being matched. It has the subclasses `Case` and `IsExpr`. @@ -31,5 +36,6 @@ - Classes `IsConstantExpr`, `IsTypeExpr` and `IsPatternExpr` are deprecated in favour of `IsExpr` - Class `Switch` models both `SwitchExpr` and `SwitchStmt` - Class `Case` models both `CaseStmt` and `SwitchCaseExpr` + - Class `UsingStmt` models both `UsingBlockStmt` and `UsingDeclStmt` ## Changes to autobuilder From f1bb8b893b7561bdd9a9a4024d26c190e2e44949 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 3 Jun 2019 17:42:08 +0100 Subject: [PATCH 12/20] C#: Fix test. --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 48 +++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 863a08040b7..e5434239a34 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1125,6 +1125,28 @@ class UsingStmt extends Stmt, @using_stmt { /** Gets a local variable declaration of this `using` statement. */ LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } + /** + * Gets an expression that is used in this `using` statement. Either an + * expression assigned to a variable, for example `File.Open("settings.xml")` + * in + * + * ``` + * using (FileStream f = File.Open("settings.xml")) { + * ... + * } + * ``` + * + * or an expression directly used, for example `File.Open("settings.xml")` + * in + * + * ``` + * using (File.Open("settings.xml")) { + * ... + * } + * ``` + */ + Expr getAnExpr() { none() } + /** * DEPRECATED: Use UsingBlockStmt.getExpr() instead. * Gets the expression directly used by this `using` statement, if any. For @@ -1178,27 +1200,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { */ override Expr getExpr() { result = this.getChild(0) } - /** - * Gets an expression that is used in this `using` statement. Either an - * expression assigned to a variable, for example `File.Open("settings.xml")` - * in - * - * ``` - * using (FileStream f = File.Open("settings.xml")) { - * ... - * } - * ``` - * - * or an expression directly used, for example `File.Open("settings.xml")` - * in - * - * ``` - * using (File.Open("settings.xml")) { - * ... - * } - * ``` - */ - Expr getAnExpr() { + override Expr getAnExpr() { result = this.getAVariableDeclExpr().getInitializer() or result = this.getExpr() @@ -1300,6 +1302,10 @@ class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { override LocalConstantDeclExpr getVariableDeclExpr(int n) { result = LocalVariableDeclStmt.super.getVariableDeclExpr(n) } + + override Expr getAnExpr() { + result = this.getAVariableDeclExpr().getInitializer() + } } /** From 20752c80c947edf23958c94adcb86e57ad925697 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 4 Jun 2019 16:59:07 +0100 Subject: [PATCH 13/20] C#: Address review comments --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 4 ++-- .../assignables/AssignableAccess.expected | 1 + .../assignables/AssignableDefinition.expected | 1 + .../ql/test/library-tests/assignables/Assignables.cs | 7 +++++++ .../library-tests/assignables/Assignables.expected | 1 + .../assignables/GetAnAssignedValue.expected | 1 + .../library-tests/csharp8/UsingDeclarations.expected | 10 ++++++++++ .../ql/test/library-tests/csharp8/UsingDeclarations.ql | 2 ++ .../DisposeNotCalledOnException.cs | 6 ++++++ .../NoDisposeCallOnLocalIDisposable.cs | 5 +++++ .../upgrade.properties | 2 +- 11 files changed, 37 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index e5434239a34..d849763baeb 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1295,11 +1295,11 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { override string toString() { result = "using ... ...;" } - override LocalConstantDeclExpr getAVariableDeclExpr() { + override LocalVariableDeclExpr getAVariableDeclExpr() { result = LocalVariableDeclStmt.super.getAVariableDeclExpr() } - override LocalConstantDeclExpr getVariableDeclExpr(int n) { + override LocalVariableDeclExpr getVariableDeclExpr(int n) { result = LocalVariableDeclStmt.super.getVariableDeclExpr(n) } diff --git a/csharp/ql/test/library-tests/assignables/AssignableAccess.expected b/csharp/ql/test/library-tests/assignables/AssignableAccess.expected index a6deb6b6be3..918456037c5 100644 --- a/csharp/ql/test/library-tests/assignables/AssignableAccess.expected +++ b/csharp/ql/test/library-tests/assignables/AssignableAccess.expected @@ -104,6 +104,7 @@ | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | read | | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | write | | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | s | write | +| Assignables.cs:138:19:138:19 | access to local variable x | Assignables.cs:138:19:138:19 | x | write | | Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:5:30:5:30 | x | write | | Discards.cs:20:32:20:32 | Boolean z | Discards.cs:20:32:20:32 | z | write | | Discards.cs:25:27:25:30 | access to parameter args | Discards.cs:23:27:23:30 | args | read | diff --git a/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected b/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected index 0d0eca393d7..f48c5bf4fb0 100644 --- a/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected +++ b/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected @@ -87,6 +87,7 @@ | Assignables.cs:132:13:132:13 | x | Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:13 | access to local variable x | Assignables.cs:132:17:132:17 | 0 | certain | | Assignables.cs:132:13:132:13 | x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | | certain | | Assignables.cs:133:29:133:29 | s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | | certain | +| Assignables.cs:138:19:138:19 | x | Assignables.cs:138:19:138:50 | MemoryStream x = ... | Assignables.cs:138:19:138:19 | access to local variable x | Assignables.cs:138:23:138:50 | object creation of type MemoryStream | certain | | Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | | Discards.cs:5:30:5:30 | | certain | | Discards.cs:5:30:5:30 | x | Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:7:13:7:17 | false | certain | | Discards.cs:19:14:19:14 | x | Discards.cs:19:9:19:29 | ... = ... | Discards.cs:19:9:19:29 | | Discards.cs:19:9:19:29 | | certain | diff --git a/csharp/ql/test/library-tests/assignables/Assignables.cs b/csharp/ql/test/library-tests/assignables/Assignables.cs index 965ba91efa9..33eb6f32826 100644 --- a/csharp/ql/test/library-tests/assignables/Assignables.cs +++ b/csharp/ql/test/library-tests/assignables/Assignables.cs @@ -132,4 +132,11 @@ class Assignables var x = 0; d(ref x, out string s); } + + void UsingDeclarations() + { + using var x = new System.IO.MemoryStream(); + } } + +// semmle-extractor-options: /langversion:8.0 diff --git a/csharp/ql/test/library-tests/assignables/Assignables.expected b/csharp/ql/test/library-tests/assignables/Assignables.expected index e848acb03ac..890c87004ba 100644 --- a/csharp/ql/test/library-tests/assignables/Assignables.expected +++ b/csharp/ql/test/library-tests/assignables/Assignables.expected @@ -95,6 +95,7 @@ | Assignables.cs:130:31:130:31 | d | | Assignables.cs:132:13:132:13 | x | | Assignables.cs:133:29:133:29 | s | +| Assignables.cs:138:19:138:19 | x | | Discards.cs:5:6:5:8 | Item1 | | Discards.cs:5:11:5:16 | Item2 | | Discards.cs:5:30:5:30 | x | diff --git a/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected b/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected index 672a1657178..af8396de8f5 100644 --- a/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected +++ b/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected @@ -37,6 +37,7 @@ | Assignables.cs:125:13:125:13 | s | Assignables.cs:125:17:125:25 | nameof(...) | | Assignables.cs:125:13:125:13 | s | Assignables.cs:126:13:126:30 | nameof(...) | | Assignables.cs:132:13:132:13 | x | Assignables.cs:132:17:132:17 | 0 | +| Assignables.cs:138:19:138:19 | x | Assignables.cs:138:23:138:50 | object creation of type MemoryStream | | Discards.cs:5:30:5:30 | x | Discards.cs:7:13:7:17 | false | | Finally.cs:7:13:7:13 | i | Finally.cs:7:17:7:17 | 0 | | Finally.cs:7:13:7:13 | i | Finally.cs:15:17:15:17 | 1 | diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected index 53bd4f957d9..408c49e25f5 100644 --- a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.expected @@ -4,13 +4,23 @@ localVars | UsingDeclarations.cs:10:26:10:30 | file3 | | UsingDeclarations.cs:10:72:10:76 | file4 | localVariableDeclarations +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | usingStmts1 | UsingDeclarations.cs:8:9:8:116 | using ... ...; | | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | | UsingDeclarations.cs:14:9:15:13 | using (...) {...} | usingStmts +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 0 | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 1 | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | usingDecls | UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | | UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | +usingExprs +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | +| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | +| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | +| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | diff --git a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql index 3e0d16e1ca8..8068af7a020 100644 --- a/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql +++ b/csharp/ql/test/library-tests/csharp8/UsingDeclarations.ql @@ -18,3 +18,5 @@ query predicate usingStmts(UsingStmt stmt, int i, LocalVariableDeclExpr decl) { } query predicate usingDecls(UsingDeclStmt stmt, int i, Expr e) { e = stmt.getChild(i) } + +query predicate usingExprs(UsingStmt stmt, Expr e) { e = stmt.getAnExpr() } diff --git a/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/DisposeNotCalledOnException.cs b/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/DisposeNotCalledOnException.cs index c22c272d776..9edd9b6ae24 100644 --- a/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/DisposeNotCalledOnException.cs +++ b/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/DisposeNotCalledOnException.cs @@ -58,6 +58,10 @@ class Test SqlConnection c1f = new SqlConnection(); Throw2(c1f); c1f.Dispose(); + + // GOOD: using declaration + using SqlConnection c2 = new SqlConnection(""); + c2.Open(); } void Throw1(SqlConnection sc) @@ -71,3 +75,5 @@ class Test return sc == null ? throw new Exception() : sc; } } + +// semmle-extractor-options: /langversion:8.0 diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index c37180318b4..aa325c33bdc 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -78,6 +78,9 @@ class Test // GOOD: Passed to a library. This is only detected in CIL. Console.SetOut(new StreamWriter("output.txt")); + // GOOD: Disposed automatically. + using var c2 = new Timer(TimerProc); + return null; } @@ -88,3 +91,5 @@ class Test { } } + +// semmle-extractor-options: /langversion:8.0 diff --git a/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties index 02a033c3472..120ca987190 100644 --- a/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties +++ b/csharp/upgrades/22d4df34563b234c6fc108ccebdffe8ae9b8e49c/upgrade.properties @@ -1,2 +1,2 @@ -description: Support for null-coalescing assignment, static local functions and using declarations. +description: Support for null-coalescing assignment, static local functions, and using declarations. compatibility: backwards From 9678f8eaba579d5c8f1865617c45b0182c1f6444 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 4 Jun 2019 18:06:42 +0100 Subject: [PATCH 14/20] C#: Fix control flow graph for using declaration statements. --- .../csharp/controlflow/ControlFlowGraph.qll | 2 +- .../csharp8/UsingControlFlow.expected | 26 +++++++++++++++++++ .../library-tests/csharp8/UsingControlFlow.ql | 10 +++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 csharp/ql/test/library-tests/csharp8/UsingControlFlow.expected create mode 100644 csharp/ql/test/library-tests/csharp8/UsingControlFlow.ql diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 2618fd4bc63..4f3b2797260 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -468,7 +468,7 @@ module ControlFlow { override ControlFlowElement getChildElement(int i) { not this instanceof GeneralCatchClause and not this instanceof FixedStmt and - not this instanceof UsingStmt and + not this instanceof UsingBlockStmt and result = this.getChild(i) or this = any(GeneralCatchClause gcc | i = 0 and result = gcc.getBlock()) diff --git a/csharp/ql/test/library-tests/csharp8/UsingControlFlow.expected b/csharp/ql/test/library-tests/csharp8/UsingControlFlow.expected new file mode 100644 index 00000000000..985f5d15b56 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/UsingControlFlow.expected @@ -0,0 +1,26 @@ +| UsingDeclarations.cs:6:10:6:30 | enter TestUsingDeclarations | UsingDeclarations.cs:7:5:16:5 | {...} | semmle.label | successor | +| UsingDeclarations.cs:7:5:16:5 | {...} | UsingDeclarations.cs:8:9:8:116 | using ... ...; | semmle.label | successor | +| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:49:8:53 | "..." | semmle.label | successor | +| UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | UsingDeclarations.cs:8:95:8:99 | "..." | semmle.label | successor | +| UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | semmle.label | successor | +| UsingDeclarations.cs:8:49:8:53 | "..." | UsingDeclarations.cs:8:56:8:68 | access to constant Open | semmle.label | successor | +| UsingDeclarations.cs:8:56:8:68 | access to constant Open | UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | semmle.label | successor | +| UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | semmle.label | successor | +| UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | semmle.label | successor | +| UsingDeclarations.cs:8:95:8:99 | "..." | UsingDeclarations.cs:8:102:8:114 | access to constant Open | semmle.label | successor | +| UsingDeclarations.cs:8:102:8:114 | access to constant Open | UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | semmle.label | successor | +| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:49:10:53 | "..." | semmle.label | successor | +| UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | UsingDeclarations.cs:10:95:10:99 | "..." | semmle.label | successor | +| UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | semmle.label | successor | +| UsingDeclarations.cs:10:49:10:53 | "..." | UsingDeclarations.cs:10:56:10:68 | access to constant Open | semmle.label | successor | +| UsingDeclarations.cs:10:56:10:68 | access to constant Open | UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | semmle.label | successor | +| UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | UsingDeclarations.cs:11:9:12:9 | {...} | semmle.label | successor | +| UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | semmle.label | successor | +| UsingDeclarations.cs:10:95:10:99 | "..." | UsingDeclarations.cs:10:102:10:114 | access to constant Open | semmle.label | successor | +| UsingDeclarations.cs:10:102:10:114 | access to constant Open | UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | semmle.label | successor | +| UsingDeclarations.cs:11:9:12:9 | {...} | UsingDeclarations.cs:14:9:15:13 | using (...) {...} | semmle.label | successor | +| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | UsingDeclarations.cs:14:30:14:34 | "..." | semmle.label | successor | +| UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | UsingDeclarations.cs:15:13:15:13 | ; | semmle.label | successor | +| UsingDeclarations.cs:14:30:14:34 | "..." | UsingDeclarations.cs:14:37:14:49 | access to constant Open | semmle.label | successor | +| UsingDeclarations.cs:14:37:14:49 | access to constant Open | UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | semmle.label | successor | +| UsingDeclarations.cs:15:13:15:13 | ; | UsingDeclarations.cs:6:10:6:30 | exit TestUsingDeclarations | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/csharp8/UsingControlFlow.ql b/csharp/ql/test/library-tests/csharp8/UsingControlFlow.ql new file mode 100644 index 00000000000..9b576914c1f --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/UsingControlFlow.ql @@ -0,0 +1,10 @@ +import csharp +import semmle.code.csharp.controlflow.ControlFlowGraph + +query predicate edges(ControlFlow::Node node1, ControlFlow::Node node2, string label, string value) { + label = "semmle.label" and + exists(ControlFlow::SuccessorType t | + node2 = node1.getASuccessorByType(t) and value = t.toString() + ) + and node1.getEnclosingCallable().hasName("TestUsingDeclarations") +} From a4876270eca338e7488fcb29cbebaab10072fc05 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 4 Jun 2019 17:07:49 +0100 Subject: [PATCH 15/20] JavaScript: Tweak `PasswordInConfigurationFile` alerts. Only highlight first line, and include the password in the alert message. --- .../src/Security/CWE-313/PasswordInConfigurationFile.ql | 8 +++++--- .../Security/CWE-313/PasswordInConfigurationFile.expected | 5 +++-- javascript/ql/test/query-tests/Security/CWE-313/tst7.yml | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql b/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql index c62072b2f20..e5ccf13a19e 100644 --- a/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql +++ b/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql @@ -12,6 +12,7 @@ */ import javascript +import semmle.javascript.RestrictedLocations /** * Holds if some JSON or YAML file contains a property with name `key` @@ -45,7 +46,7 @@ predicate exclude(File f) { f.getExtension().toLowerCase() = "raml" } -from string key, string val, Locatable valElement +from string key, string val, Locatable valElement, string pwd where config(key, val, valElement) and val != "" and @@ -53,13 +54,14 @@ where not val.regexpMatch(Templating::getDelimiterMatchingRegexp()) and ( key.toLowerCase() = "password" and + pwd = val and // exclude interpolations of environment variables not val.regexpMatch("\\$.*|%.*%") or key.toLowerCase() != "readme" and // look for `password=...`, but exclude `password=;`, `password="$(...)"`, // `password=%s` and `password==` - val.regexpMatch("(?is).*password\\s*=(?!\\s*;)(?!\"?[$`])(?!%s)(?!=).*") + pwd = val.regexpCapture("(?is).*password\\s*=\\s*(?!;|\"?[$`]|%s|=)(\\S+).*", 1) ) and not exclude(valElement.getFile()) -select valElement, "Avoid plaintext passwords in configuration files." +select (FirstLineOf)valElement, "Hard-coded password '" + pwd + "' in configuration file." diff --git a/javascript/ql/test/query-tests/Security/CWE-313/PasswordInConfigurationFile.expected b/javascript/ql/test/query-tests/Security/CWE-313/PasswordInConfigurationFile.expected index c2164960179..8c4b33e1830 100644 --- a/javascript/ql/test/query-tests/Security/CWE-313/PasswordInConfigurationFile.expected +++ b/javascript/ql/test/query-tests/Security/CWE-313/PasswordInConfigurationFile.expected @@ -1,2 +1,3 @@ -| mysql-config.json:4:16:4:23 | "secret" | Avoid plaintext passwords in configuration files. | -| tst4.json:2:10:2:38 | "script ... ecret'" | Avoid plaintext passwords in configuration files. | +| mysql-config.json:4:16:4:23 | "secret" | Hard-coded password 'secret' in configuration file. | +| tst4.json:2:10:2:38 | "script ... ecret'" | Hard-coded password ''secret'' in configuration file. | +| tst7.yml:2:9:2:6 | \| | Hard-coded password 'abc' in configuration file. | diff --git a/javascript/ql/test/query-tests/Security/CWE-313/tst7.yml b/javascript/ql/test/query-tests/Security/CWE-313/tst7.yml index 5813ec0dd37..336ef4165d5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-313/tst7.yml +++ b/javascript/ql/test/query-tests/Security/CWE-313/tst7.yml @@ -1 +1,7 @@ password: $$SOME_VAR +config: | + [mail] + host = smtp.mydomain.com + port = 25 + username = sample_admin@mydomain.com + password = abc From d723ab76d8c0cd005ddd93ff484e4c80c32f9885 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 4 Jun 2019 17:12:02 +0100 Subject: [PATCH 16/20] JavaScript: Fix `getDelimiterMatchingRegexp` to work on multi-line strings. --- .../ql/src/semmle/javascript/frameworks/Templating.qll | 2 +- javascript/ql/test/query-tests/Security/CWE-313/tst8.yml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-313/tst8.yml diff --git a/javascript/ql/src/semmle/javascript/frameworks/Templating.qll b/javascript/ql/src/semmle/javascript/frameworks/Templating.qll index 08097dc4693..d9b45e1a421 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Templating.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Templating.qll @@ -37,6 +37,6 @@ module Templating { * storing it in its first (and only) capture group. */ string getDelimiterMatchingRegexp() { - result = ".*(" + concat("\\Q" + getADelimiter() + "\\E", "|") + ").*" + result = "(?s).*(" + concat("\\Q" + getADelimiter() + "\\E", "|") + ").*" } } diff --git a/javascript/ql/test/query-tests/Security/CWE-313/tst8.yml b/javascript/ql/test/query-tests/Security/CWE-313/tst8.yml new file mode 100644 index 00000000000..188798fe331 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-313/tst8.yml @@ -0,0 +1,6 @@ +config: | + [mail] + host = smtp.mydomain.com + port = 25 + username = {{username}} + password = {{pwd}} From d233cea79d2012f39848ce9c705425cc29ed3f84 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 4 Jun 2019 17:06:38 +0100 Subject: [PATCH 17/20] JavaScript: Lower precision of `PasswordInConfigurationFile`. In spite of recent improvements, this query is still too noisy to show by default. --- change-notes/1.21/analysis-javascript.md | 2 +- .../ql/src/Security/CWE-313/PasswordInConfigurationFile.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/change-notes/1.21/analysis-javascript.md b/change-notes/1.21/analysis-javascript.md index 8a63c8df65c..c4af8bf7d71 100644 --- a/change-notes/1.21/analysis-javascript.md +++ b/change-notes/1.21/analysis-javascript.md @@ -40,7 +40,7 @@ | Expression has no effect | Fewer false-positive results | This rule now treats uses of `Object.defineProperty` more conservatively. | | Incomplete regular expression for hostnames | More results | This rule now tracks regular expressions for host names further. | | Incomplete string escaping or encoding | More results | This rule now considers the flow of regular expressions literals, and it no longer flags the removal of trailing newlines. | -| Password in configuration file | Fewer false positive results | This query now excludes passwords that are inserted into the configuration file using a templating mechanism or read from environment variables. | +| Password in configuration file | Fewer false positive results | This query now excludes passwords that are inserted into the configuration file using a templating mechanism or read from environment variables. Results are no longer shown on LGTM by default. | | Replacement of a substring with itself | More results | This rule now considers the flow of regular expressions literals. | | Server-side URL redirect | Fewer false-positive results | This rule now treats URLs as safe in more cases where the hostname cannot be tampered with. | | Type confusion through parameter tampering | Fewer false-positive results | This rule now recognizes additional emptiness checks. | diff --git a/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql b/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql index e5ccf13a19e..695f6fc2937 100644 --- a/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql +++ b/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql @@ -3,7 +3,7 @@ * @description Storing unencrypted passwords in configuration files is unsafe. * @kind problem * @problem.severity warning - * @precision high + * @precision medium * @id js/password-in-configuration-file * @tags security * external/cwe/cwe-256 From 98c5dc194b7fe329366c9182dc85cf8d2ece2bd6 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 5 Jun 2019 09:16:12 +0200 Subject: [PATCH 18/20] Java: Rename to selector as per review comment. --- java/ql/src/semmle/code/java/Statement.qll | 2 +- java/ql/src/semmle/code/java/controlflow/Guards.qll | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index 2dfa5d26456..2f98615b243 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -427,7 +427,7 @@ class SwitchCase extends Stmt, @case { * Gets the expression of the surrounding switch that this case is compared * against. */ - Expr getTestExpr() { + Expr getSelectorExpr() { result = this.getSwitch().getExpr() or result = this.getSwitchExpr().getExpr() } diff --git a/java/ql/src/semmle/code/java/controlflow/Guards.qll b/java/ql/src/semmle/code/java/controlflow/Guards.qll index 976f90c17b1..ac7d4cb8150 100644 --- a/java/ql/src/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/src/semmle/code/java/controlflow/Guards.qll @@ -127,7 +127,7 @@ class Guard extends ExprParent { branch = true and bb2.getFirstNode() = sc.getControlFlowNode() and pred = sc.getControlFlowNode().getAPredecessor() and - pred.(Expr).getParent*() = sc.getTestExpr() and + pred.(Expr).getParent*() = sc.getSelectorExpr() and bb1 = pred.getBasicBlock() ) or @@ -161,12 +161,12 @@ class Guard extends ExprParent { } private predicate switchCaseControls(SwitchCase sc, BasicBlock bb) { - exists(BasicBlock caseblock, Expr switchTest | - switchTest = sc.getTestExpr() and + exists(BasicBlock caseblock, Expr selector | + selector = sc.getSelectorExpr() and caseblock.getFirstNode() = sc.getControlFlowNode() and caseblock.bbDominates(bb) and forall(ControlFlowNode pred | pred = sc.getControlFlowNode().getAPredecessor() | - pred.(Expr).getParent*() = switchTest + pred.(Expr).getParent*() = selector ) ) } @@ -255,7 +255,7 @@ private predicate equalityGuard(Guard g, Expr e1, Expr e2, boolean polarity) { exists(ConstCase cc | cc = g and polarity = true and - cc.getTestExpr().getProperExpr() = e1 and + cc.getSelectorExpr().getProperExpr() = e1 and cc.getValue() = e2 and strictcount(cc.getValue(_)) = 1 ) From c88359b9c777231087b412134a4e775265e730de Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 5 Jun 2019 09:42:48 +0100 Subject: [PATCH 19/20] C#: Fix test. --- .../library-tests/assignables/AssignableDefinitionNode.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/ql/test/library-tests/assignables/AssignableDefinitionNode.expected b/csharp/ql/test/library-tests/assignables/AssignableDefinitionNode.expected index 2962574af98..0d187a44566 100644 --- a/csharp/ql/test/library-tests/assignables/AssignableDefinitionNode.expected +++ b/csharp/ql/test/library-tests/assignables/AssignableDefinitionNode.expected @@ -86,6 +86,7 @@ | Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:17 | Int32 x = ... | | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:9:133:30 | delegate call | | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:9:133:30 | delegate call | +| Assignables.cs:138:19:138:50 | MemoryStream x = ... | Assignables.cs:138:19:138:50 | MemoryStream x = ... | | Discards.cs:5:30:5:30 | x | Discards.cs:5:19:5:19 | enter f | | Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:17 | ... = ... | | Discards.cs:13:9:13:20 | ... = ... | Discards.cs:13:9:13:20 | ... = ... | From e757bce96e662184ec2af18dc15ab7c501493564 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 5 Jun 2019 12:56:36 +0100 Subject: [PATCH 20/20] Python: Fix up 'import failure' analysis query. --- python/ql/src/analysis/ImportFailure.ql | 30 +++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/python/ql/src/analysis/ImportFailure.ql b/python/ql/src/analysis/ImportFailure.ql index 38801d8d004..c50b5c6e18c 100644 --- a/python/ql/src/analysis/ImportFailure.ql +++ b/python/ql/src/analysis/ImportFailure.ql @@ -57,15 +57,37 @@ predicate ok_to_fail(ImportExpr ie) { os_specific_import(ie) != get_os() } + +class VersionTest extends @py_flow_node { + + VersionTest() { + exists(string name | + name.matches("%version%") and + this.(CompareNode).getAChild+().pointsTo(Module::named("sys").attr(name)) + ) + } + + string toString() { + result = "VersionTest" + } + +} + +/** A guard on the version of the Python interpreter */ +class VersionGuard extends ConditionBlock { + + VersionGuard() { + this.getLastNode() instanceof VersionTest + } + +} + from ImportExpr ie where not ie.refersTo(_) and exists(Context c | c.appliesTo(ie.getAFlowNode())) and not ok_to_fail(ie) and not exists(VersionGuard guard | - if guard.isTrue() then - guard.controls(ie.getAFlowNode().getBasicBlock(), false) - else - guard.controls(ie.getAFlowNode().getBasicBlock(), true) + guard.controls(ie.getAFlowNode().getBasicBlock(), _) ) select ie, "Unable to resolve import of '" + ie.getImportedModuleName() + "'."