diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md
index 54954e0f70a..78d4aee4ed7 100644
--- a/change-notes/1.24/analysis-cpp.md
+++ b/change-notes/1.24/analysis-cpp.md
@@ -19,6 +19,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
| Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
| Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
| Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. |
+| No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. |
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. |
diff --git a/change-notes/1.24/analysis-csharp.md b/change-notes/1.24/analysis-csharp.md
index 5859d97afb6..27b0b8f5b4a 100644
--- a/change-notes/1.24/analysis-csharp.md
+++ b/change-notes/1.24/analysis-csharp.md
@@ -29,6 +29,7 @@ The following changes in version 1.24 affect C# analysis in all applications.
* Tuple expressions, for example `(int,bool)` in `default((int,bool))` are now extracted correctly.
* Expression nullability flow state is extracted.
* Implicitly typed `stackalloc` expressions are now extracted correctly.
+* The difference between `stackalloc` array creations and normal array creations is extracted.
## Changes to libraries
@@ -39,5 +40,6 @@ The following changes in version 1.24 affect C# analysis in all applications.
* The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls.
* [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods.
* Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`.
+* `stackalloc` array creations are now represented by the QL class `Stackalloc`. Previously they were represented by the class `ArrayCreation`.
## Changes to autobuilder
diff --git a/change-notes/1.24/analysis-python.md b/change-notes/1.24/analysis-python.md
new file mode 100644
index 00000000000..a4a643944c7
--- /dev/null
+++ b/change-notes/1.24/analysis-python.md
@@ -0,0 +1,37 @@
+# Improvements to Python analysis
+
+The following changes in version 1.24 affect Python analysis in all applications.
+
+## General improvements
+
+## New queries
+
+| **Query** | **Tags** | **Purpose** |
+|-----------------------------|-----------|--------------------------------------------------------------------|
+
+## Changes to existing queries
+
+| **Query** | **Expected impact** | **Change** |
+|----------------------------|------------------------|------------------------------------------------------------------|
+
+### Web framework support
+
+The QL-library support for the web frameworks Bottle, CherryPy, Falcon, Pyramid, TurboGears, Tornado, and Twisted have
+been fixed so they provide a proper HttpRequestTaintSource, instead of a TaintSource. This will enable results for the following queries:
+
+- py/path-injection
+- py/command-line-injection
+- py/reflective-xss
+- py/sql-injection
+- py/code-injection
+- py/unsafe-deserialization
+- py/url-redirection
+
+The QL-library support for the web framework Twisted have been fixed so they provide a proper
+HttpResponseTaintSink, instead of a TaintSink. This will enable results for the following
+queries:
+
+- py/reflective-xss
+- py/stack-trace-exposure
+
+## Changes to libraries
diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
index 79a4418125b..7ee6acdcd59 100644
--- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
+++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
@@ -22,16 +22,25 @@ import semmle.code.cpp.models.interfaces.Allocation
predicate terminationProblem(AllocationExpr malloc, string msg) {
// malloc(strlen(...))
exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getSizeExpr())) and
- // flows into a null-terminated string function
+ // flows to a call that implies this is a null-terminated string
exists(ArrayFunction af, FunctionCall fc, int arg |
DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and
fc.getTarget() = af and
(
- // null terminated string
+ // flows into null terminated string argument
af.hasArrayWithNullTerminator(arg)
or
- // likely a null terminated string (such as `strcpy`, `strcat`)
+ // flows into likely null terminated string argument (such as `strcpy`, `strcat`)
af.hasArrayWithUnknownSize(arg)
+ or
+ // flows into string argument to a formatting function (such as `printf`)
+ exists(int n, FormatLiteral fl |
+ fc.getArgument(arg) = fc.(FormattingFunctionCall).getConversionArgument(n) and
+ fl = fc.(FormattingFunctionCall).getFormat() and
+ fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
+ not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
+ not fl.hasPrecision(n) // exclude: `%.*s`
+ )
)
) and
msg = "This allocation does not include space to null-terminate the string."
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
index 41d7a1401b5..668512cecde 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
@@ -335,6 +335,12 @@ private Element adjustedSink(DataFlow::Node sink) {
// For compatibility, send flow into a `NotExpr` even if it's part of a
// short-circuiting condition and thus might get skipped.
result.(NotExpr).getOperand() = sink.asExpr()
+ or
+ // Taint postfix and prefix crement operations when their operand is tainted.
+ result.(CrementOperation).getAnOperand() = sink.asExpr()
+ or
+ // Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
+ result.(AssignOperation).getAnOperand() = sink.asExpr()
}
predicate tainted(Expr source, Element tainted) {
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll
index ed46d81ac06..4667714d418 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll
@@ -11,13 +11,19 @@ cached
private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
} or
TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ (
+ strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
+ or
+ tag instanceof UnmodeledUseOperandTag
+ )
} or
TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll
index 9e5e74012cd..28042886742 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll
@@ -2,10 +2,10 @@ private import ValueNumberingImports
private import cpp
newtype TValueNumber =
- TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
- variableAddressValueNumber(_, irFunc, var)
+ TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
+ variableAddressValueNumber(_, irFunc, ast)
} or
- TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
+ TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
initializeParameterValueNumber(_, irFunc, var)
} or
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
@@ -100,17 +100,23 @@ private predicate numberableInstruction(Instruction instr) {
}
private predicate variableAddressValueNumber(
- VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
+ VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
) {
instr.getEnclosingIRFunction() = irFunc and
- instr.getIRVariable() = var
+ // The underlying AST element is used as value-numbering key instead of the
+ // `IRVariable` to work around a problem where a variable or expression with
+ // multiple types gives rise to multiple `IRVariable`s.
+ instr.getIRVariable().getAST() = ast
}
private predicate initializeParameterValueNumber(
- InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
+ InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
) {
instr.getEnclosingIRFunction() = irFunc and
- instr.getIRVariable() = var
+ // The underlying AST element is used as value-numbering key instead of the
+ // `IRVariable` to work around a problem where a variable or expression with
+ // multiple types gives rise to multiple `IRVariable`s.
+ instr.getIRVariable().getAST() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
@@ -236,12 +242,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
exists(IRFunction irFunc |
irFunc = instr.getEnclosingIRFunction() and
(
- exists(IRVariable var |
- variableAddressValueNumber(instr, irFunc, var) and
- result = TVariableAddressValueNumber(irFunc, var)
+ exists(Language::AST ast |
+ variableAddressValueNumber(instr, irFunc, ast) and
+ result = TVariableAddressValueNumber(irFunc, ast)
)
or
- exists(IRVariable var |
+ exists(Language::AST var |
initializeParameterValueNumber(instr, irFunc, var) and
result = TInitializeParameterValueNumber(irFunc, var)
)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll
index ed46d81ac06..4667714d418 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll
@@ -11,13 +11,19 @@ cached
private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
} or
TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ (
+ strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
+ or
+ tag instanceof UnmodeledUseOperandTag
+ )
} or
TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
index 9e5e74012cd..28042886742 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
@@ -2,10 +2,10 @@ private import ValueNumberingImports
private import cpp
newtype TValueNumber =
- TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
- variableAddressValueNumber(_, irFunc, var)
+ TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
+ variableAddressValueNumber(_, irFunc, ast)
} or
- TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
+ TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
initializeParameterValueNumber(_, irFunc, var)
} or
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
@@ -100,17 +100,23 @@ private predicate numberableInstruction(Instruction instr) {
}
private predicate variableAddressValueNumber(
- VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
+ VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
) {
instr.getEnclosingIRFunction() = irFunc and
- instr.getIRVariable() = var
+ // The underlying AST element is used as value-numbering key instead of the
+ // `IRVariable` to work around a problem where a variable or expression with
+ // multiple types gives rise to multiple `IRVariable`s.
+ instr.getIRVariable().getAST() = ast
}
private predicate initializeParameterValueNumber(
- InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
+ InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
) {
instr.getEnclosingIRFunction() = irFunc and
- instr.getIRVariable() = var
+ // The underlying AST element is used as value-numbering key instead of the
+ // `IRVariable` to work around a problem where a variable or expression with
+ // multiple types gives rise to multiple `IRVariable`s.
+ instr.getIRVariable().getAST() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
@@ -236,12 +242,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
exists(IRFunction irFunc |
irFunc = instr.getEnclosingIRFunction() and
(
- exists(IRVariable var |
- variableAddressValueNumber(instr, irFunc, var) and
- result = TVariableAddressValueNumber(irFunc, var)
+ exists(Language::AST ast |
+ variableAddressValueNumber(instr, irFunc, ast) and
+ result = TVariableAddressValueNumber(irFunc, ast)
)
or
- exists(IRVariable var |
+ exists(Language::AST var |
initializeParameterValueNumber(instr, irFunc, var) and
result = TInitializeParameterValueNumber(irFunc, var)
)
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll
index ed46d81ac06..4667714d418 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll
@@ -11,13 +11,19 @@ cached
private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
} or
TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ (
+ strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
+ or
+ tag instanceof UnmodeledUseOperandTag
+ )
} or
TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
index 9e5e74012cd..28042886742 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
@@ -2,10 +2,10 @@ private import ValueNumberingImports
private import cpp
newtype TValueNumber =
- TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
- variableAddressValueNumber(_, irFunc, var)
+ TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
+ variableAddressValueNumber(_, irFunc, ast)
} or
- TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
+ TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
initializeParameterValueNumber(_, irFunc, var)
} or
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
@@ -100,17 +100,23 @@ private predicate numberableInstruction(Instruction instr) {
}
private predicate variableAddressValueNumber(
- VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
+ VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
) {
instr.getEnclosingIRFunction() = irFunc and
- instr.getIRVariable() = var
+ // The underlying AST element is used as value-numbering key instead of the
+ // `IRVariable` to work around a problem where a variable or expression with
+ // multiple types gives rise to multiple `IRVariable`s.
+ instr.getIRVariable().getAST() = ast
}
private predicate initializeParameterValueNumber(
- InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
+ InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
) {
instr.getEnclosingIRFunction() = irFunc and
- instr.getIRVariable() = var
+ // The underlying AST element is used as value-numbering key instead of the
+ // `IRVariable` to work around a problem where a variable or expression with
+ // multiple types gives rise to multiple `IRVariable`s.
+ instr.getIRVariable().getAST() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
@@ -236,12 +242,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
exists(IRFunction irFunc |
irFunc = instr.getEnclosingIRFunction() and
(
- exists(IRVariable var |
- variableAddressValueNumber(instr, irFunc, var) and
- result = TVariableAddressValueNumber(irFunc, var)
+ exists(Language::AST ast |
+ variableAddressValueNumber(instr, irFunc, ast) and
+ result = TVariableAddressValueNumber(irFunc, ast)
)
or
- exists(IRVariable var |
+ exists(Language::AST var |
initializeParameterValueNumber(instr, irFunc, var) and
result = TInitializeParameterValueNumber(irFunc, var)
)
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected
index de52927e1e8..1476b2c7d95 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected
@@ -5,6 +5,7 @@
| test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. |
+| test.cpp:55:28:55:33 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:71:28:71:33 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:79:28:79:33 | call to malloc | This allocation does not include space to null-terminate the string. |
diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp
index b0db8dea6ef..996938c6324 100644
--- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp
+++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp
@@ -51,7 +51,7 @@ void decode(char *dest, char *src);
void wdecode(wchar_t *dest, wchar_t *src);
void bad4(char *str) {
- // BAD -- zero-termination proved by wprintf (as parameter) [NOT DETECTED]
+ // BAD -- zero-termination proved by wprintf (as parameter)
char *buffer = (char *)malloc(strlen(str));
decode(buffer, str);
wprintf(L"%s", buffer);
@@ -107,3 +107,19 @@ void bad9(wchar_t *wstr) {
wcscpy(wbuffer, wstr);
delete wbuffer;
}
+
+void good3(char *str) {
+ // GOOD -- zero-termination not required for this printf
+ char *buffer = (char *)malloc(strlen(str));
+ decode(buffer, str);
+ wprintf(L"%p", buffer);
+ free(buffer);
+}
+
+void good4(char *str) {
+ // GOOD -- zero-termination not required for this printf
+ char *buffer = (char *)malloc(strlen(str));
+ decode(buffer, str);
+ wprintf(L"%.*s", strlen(str), buffer);
+ free(buffer);
+}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs
index a08019ce338..a4b1a4beb09 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs
@@ -90,6 +90,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public override InitializerExpressionSyntax Initializer => Syntax.Initializer;
+ protected override void PopulateExpression(TextWriter trapFile)
+ {
+ base.PopulateExpression(trapFile);
+ trapFile.stackalloc_array_creation(this);
+ }
+
public static Expression Create(ExpressionNodeInfo info) => new StackAllocArrayCreation(info).TryPopulate();
}
@@ -103,6 +109,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1));
trapFile.implicitly_typed_array_creation(this);
+ trapFile.stackalloc_array_creation(this);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs
index e83cd689596..6d0f14a014e 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs
@@ -1,3 +1,4 @@
+using System;
using System.IO;
using Microsoft.CodeAnalysis;
@@ -9,10 +10,12 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
- trapFile.WriteSubId(Location);
- trapFile.Write('_');
- trapFile.Write(symbol.Name);
- trapFile.Write(";localvar");
+ throw new InvalidOperationException();
+ }
+
+ public override void WriteQuotedId(TextWriter trapFile)
+ {
+ trapFile.Write('*');
}
public override void Populate(TextWriter trapFile) { }
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs
index d263a0e2868..4b24833337c 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs
@@ -466,6 +466,11 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("specific_type_parameter_nullability", constraints, baseType, nullability);
}
+ internal static void stackalloc_array_creation(this TextWriter trapFile, Expression array)
+ {
+ trapFile.WriteTuple("stackalloc_array_creation", array);
+ }
+
internal static void stmt_location(this TextWriter trapFile, Statement stmt, Location location)
{
trapFile.WriteTuple("stmt_location", stmt, location);
diff --git a/csharp/extractor/Semmle.Extraction/Symbol.cs b/csharp/extractor/Semmle.Extraction/Symbol.cs
index 23c340b425e..57bb1ed11ad 100644
--- a/csharp/extractor/Semmle.Extraction/Symbol.cs
+++ b/csharp/extractor/Semmle.Extraction/Symbol.cs
@@ -53,7 +53,7 @@ namespace Semmle.Extraction
public abstract void WriteId(System.IO.TextWriter trapFile);
- public void WriteQuotedId(TextWriter trapFile)
+ public virtual void WriteQuotedId(TextWriter trapFile)
{
trapFile.Write("@\"");
WriteId(trapFile);
diff --git a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
index 2f2b29d33a6..7b875faae67 100644
--- a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
+++ b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
@@ -11,6 +11,7 @@
import semmle.code.csharp.serialization.Serialization
import semmle.code.csharp.controlflow.Guards
+import semmle.code.csharp.dataflow.DataFlow
/**
* The result is a write to the field `f`, assigning it the value
@@ -29,7 +30,11 @@ GuardedExpr checkedWrite(Field f, Variable v, IfStmt check) {
Expr uncheckedWrite(Callable callable, Field f) {
result = f.getAnAssignedValue() and
result.getEnclosingCallable() = callable and
- not callable.calls*(checkedWrite(f, _, _).getEnclosingCallable())
+ not callable.calls*(checkedWrite(f, _, _).getEnclosingCallable()) and
+ // Exclude object creations because they were not deserialized
+ not exists(Expr src | DataFlow::localExprFlow(src, result) |
+ src instanceof ObjectCreation or src.hasValue()
+ )
}
from BinarySerializableType t, Field f, IfStmt check, Expr write, Expr unsafeWrite
diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll
index 164a77f584b..f0aebc389d0 100644
--- a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll
+++ b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll
@@ -372,6 +372,13 @@ class ArrayCreation extends Expr, @array_creation_expr {
override string toString() { result = "array creation of type " + this.getType().getName() }
}
+/**
+ * A `stackalloc` array creation, for example `stackalloc char[] { 'x', 'y' }`.
+ */
+class Stackalloc extends ArrayCreation {
+ Stackalloc() { stackalloc_array_creation(this) }
+}
+
/**
* An anonymous function. Either a lambda expression (`LambdaExpr`) or an
* anonymous method expression (`AnonymousMethodExpr`).
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll
index ed46d81ac06..4667714d418 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll
@@ -11,13 +11,19 @@ cached
private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
} or
TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ (
+ strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
+ or
+ tag instanceof UnmodeledUseOperandTag
+ )
} or
TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll
index ed46d81ac06..4667714d418 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll
@@ -11,13 +11,19 @@ cached
private newtype TOperand =
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
} or
TNonPhiMemoryOperand(
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
) {
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
- not Construction::isInCycle(useInstr)
+ not Construction::isInCycle(useInstr) and
+ (
+ strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
+ or
+ tag instanceof UnmodeledUseOperandTag
+ )
} or
TPhiOperand(
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme
index cf21dd4151d..ad622770b3c 100644
--- a/csharp/ql/src/semmlecode.csharp.dbscheme
+++ b/csharp/ql/src/semmlecode.csharp.dbscheme
@@ -1084,6 +1084,9 @@ implicitly_typed_array_creation(
explicitly_sized_array_creation(
unique int id: @array_creation_expr ref);
+stackalloc_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*/);
diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats
index 00ad0d841f9..23525a6a24e 100644
--- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats
+++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats
@@ -28440,6 +28440,17 @@
+stackalloc_array_creation
+50
+
+
+id
+50
+
+
+
+
+
mutator_invocation_mode
0
diff --git a/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected b/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected
index 7d3101e1522..df5891b0b8e 100644
--- a/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected
+++ b/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.expected
@@ -1,6 +1,20 @@
+arrayCreation
| csharp73.cs:9:20:9:49 | array creation of type Char* | 0 | csharp73.cs:9:20:9:49 | 2 |
| csharp73.cs:10:20:10:45 | array creation of type Char* | 0 | csharp73.cs:10:36:10:36 | 1 |
| csharp73.cs:11:20:11:37 | array creation of type Char[] | 0 | csharp73.cs:11:20:11:37 | 1 |
| csharp73.cs:12:20:12:38 | array creation of type Char* | 0 | csharp73.cs:12:36:12:37 | 10 |
| csharp73.cs:13:20:13:31 | array creation of type Char[] | 0 | csharp73.cs:13:29:13:30 | 10 |
| csharp73.cs:22:23:22:33 | array creation of type Int32[] | 0 | csharp73.cs:22:31:22:32 | 10 |
+arrayElement
+| csharp73.cs:9:20:9:49 | array creation of type Char* | 0 | csharp73.cs:9:40:9:42 | x |
+| csharp73.cs:9:20:9:49 | array creation of type Char* | 1 | csharp73.cs:9:45:9:47 | y |
+| csharp73.cs:10:20:10:45 | array creation of type Char* | 0 | csharp73.cs:10:41:10:43 | x |
+| csharp73.cs:11:20:11:37 | array creation of type Char[] | 0 | csharp73.cs:11:33:11:35 | x |
+| csharp73.cs:14:20:14:43 | array creation of type Int32* | 0 | csharp73.cs:14:35:14:35 | 1 |
+| csharp73.cs:14:20:14:43 | array creation of type Int32* | 1 | csharp73.cs:14:38:14:38 | 2 |
+| csharp73.cs:14:20:14:43 | array creation of type Int32* | 2 | csharp73.cs:14:41:14:41 | 3 |
+stackalloc
+| csharp73.cs:9:20:9:49 | array creation of type Char* |
+| csharp73.cs:10:20:10:45 | array creation of type Char* |
+| csharp73.cs:12:20:12:38 | array creation of type Char* |
+| csharp73.cs:14:20:14:43 | array creation of type Int32* |
diff --git a/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.ql b/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.ql
index 38aceeda8c3..4fc41227fab 100644
--- a/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.ql
+++ b/csharp/ql/test/library-tests/csharp7.3/ArrayCreations.ql
@@ -1,4 +1,11 @@
import csharp
-from ArrayCreation creation, int i
-select creation, i, creation.getLengthArgument(i)
+query predicate arrayCreation(ArrayCreation creation, int i, Expr length) {
+ length = creation.getLengthArgument(i)
+}
+
+query predicate arrayElement(ArrayCreation array, int i, Expr element) {
+ element = array.getInitializer().getElement(i)
+}
+
+query predicate stackalloc(Stackalloc a) { any() }
diff --git a/csharp/ql/test/library-tests/csharp7.3/ArrayElements.expected b/csharp/ql/test/library-tests/csharp7.3/ArrayElements.expected
deleted file mode 100644
index cd7bcefbf5f..00000000000
--- a/csharp/ql/test/library-tests/csharp7.3/ArrayElements.expected
+++ /dev/null
@@ -1,7 +0,0 @@
-| csharp73.cs:9:20:9:49 | array creation of type Char* | 0 | csharp73.cs:9:40:9:42 | x |
-| csharp73.cs:9:20:9:49 | array creation of type Char* | 1 | csharp73.cs:9:45:9:47 | y |
-| csharp73.cs:10:20:10:45 | array creation of type Char* | 0 | csharp73.cs:10:41:10:43 | x |
-| csharp73.cs:11:20:11:37 | array creation of type Char[] | 0 | csharp73.cs:11:33:11:35 | x |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* | 0 | csharp73.cs:14:35:14:35 | 1 |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* | 1 | csharp73.cs:14:38:14:38 | 2 |
-| csharp73.cs:14:20:14:43 | array creation of type Int32* | 2 | csharp73.cs:14:41:14:41 | 3 |
diff --git a/csharp/ql/test/library-tests/csharp7.3/ArrayElements.ql b/csharp/ql/test/library-tests/csharp7.3/ArrayElements.ql
deleted file mode 100644
index edc11606e83..00000000000
--- a/csharp/ql/test/library-tests/csharp7.3/ArrayElements.ql
+++ /dev/null
@@ -1,4 +0,0 @@
-import csharp
-
-from ArrayCreation array, int i
-select array, i, array.getInitializer().getElement(i)
diff --git a/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksBypass.cs b/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksBypass.cs
index 76d8fda8e8f..ffc89563916 100644
--- a/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksBypass.cs
+++ b/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksBypass.cs
@@ -10,14 +10,14 @@ public class Test1
{
if (v == "valid")
{
- f = v /* safe write */;
+ f = v; // GOOD
}
}
[OnDeserializing]
public void Deserialize()
{
- f = "invalid" /* unsafe write */;
+ f = $"invalid"; // BAD
}
}
@@ -30,19 +30,19 @@ public class Test2
{
if (v == "valid")
{
- f = v /* safe write */;
+ f = v; // GOOD
}
}
[OnDeserializing]
public void Deserialize()
{
- var v = "invalid";
- f = v /* unsafe write -- false negative */;
+ var v = $"invalid";
+ f = v; // BAD: False negative
if (v == "valid")
{
- f = v; /* safe write */
+ f = v; // GOOD
}
}
}
@@ -56,25 +56,25 @@ public class Test3
{
if (v == "valid")
{
- f = v /* safe write */;
+ f = v; // GOOD
}
}
[OnDeserializing]
public void Deserialize()
{
- var v = "invalid";
- f = v /* unsafe write -- false negative */;
+ var v = $"invalid";
+ f = v; // GOOD: False negative
Assign(v);
}
private void Assign(string v)
{
- f = v /* unsafe write -- false negative */;
+ f = v; // GOOD: False negative
if (v == "valid")
{
- f = v /* safe write */;
+ f = v; // GOOD
}
}
}
@@ -88,21 +88,21 @@ public class Test4
{
if (v == "valid")
{
- f = v /* safe write */;
+ f = v; // GOOD
}
}
[OnDeserializing]
public void Deserialize()
{
- var v = "invalid";
+ var v = $"invalid";
if (v == "valid")
Assign(v);
}
private void Assign(string v)
{
- f = v /* safe write */;
+ f = v; // GOOD
}
}
@@ -115,13 +115,13 @@ public class Test5 : ISerializable
{
if (age < 0)
throw new ArgumentException(nameof(age));
- Age = age /* safe write */;
+ Age = age; // GOOD
}
[OnDeserializing]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
- Age = info.GetInt32("age"); /* unsafe write */;
+ Age = info.GetInt32("age"); // BAD
}
}
@@ -134,7 +134,7 @@ public class Test6 : ISerializable
{
if (age < 0)
throw new ArgumentException(nameof(age));
- Age = age /* safe write */;
+ Age = age; // GOOD
}
[OnDeserializing]
@@ -143,7 +143,7 @@ public class Test6 : ISerializable
int age = info.GetInt32("age");
if (age < 0)
throw new SerializationException("age");
- Age = age; /* safe write */;
+ Age = age; // GOOD
}
}
@@ -156,7 +156,7 @@ public class Test7 : ISerializable
{
if (age < 0)
throw new ArgumentException(nameof(age));
- Age = age /* safe write */;
+ Age = age; // GOOD
}
[OnDeserializing]
@@ -165,6 +165,27 @@ public class Test7 : ISerializable
int age = info.GetInt32("age");
if (false)
throw new SerializationException("age");
- Age = age; /* unsafe write */;
+ Age = age; // BAD
+ }
+}
+
+[Serializable]
+public class Test8 : ISerializable
+{
+ string Options;
+
+ public int Age;
+
+ public Test8(string options)
+ {
+ if (options == null)
+ throw new ArgumentNullException(nameof(options));
+ Options = options; // GOOD
+ }
+
+ [OnDeserializing]
+ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ Options = new string(""); // GOOD: A created object
}
}
diff --git a/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksbypass.expected b/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksbypass.expected
index e9b03d3aed2..637720fbc64 100644
--- a/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksbypass.expected
+++ b/csharp/ql/test/query-tests/Security Features/CWE-020/RuntimeChecksbypass.expected
@@ -1,4 +1,4 @@
-| RuntimeChecksBypass.cs:20:13:20:21 | "invalid" | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:7:19:7:19 | f | f | RuntimeChecksBypass.cs:11:9:14:9 | if (...) ... | check |
+| RuntimeChecksBypass.cs:20:13:20:22 | $"..." | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:7:19:7:19 | f | f | RuntimeChecksBypass.cs:11:9:14:9 | if (...) ... | check |
| RuntimeChecksBypass.cs:124:15:124:34 | call to method GetInt32 | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:112:16:112:18 | Age | Age | RuntimeChecksBypass.cs:116:9:117:53 | if (...) ... | check |
| RuntimeChecksBypass.cs:168:15:168:17 | access to local variable age | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:153:16:153:18 | Age | Age | RuntimeChecksBypass.cs:157:9:158:53 | if (...) ... | check |
| RuntimeChecksBypassBad.cs:19:15:19:34 | call to method GetInt32 | This write to $@ may be circumventing a $@. | RuntimeChecksBypassBad.cs:7:16:7:18 | Age | Age | RuntimeChecksBypassBad.cs:11:9:12:53 | if (...) ... | check |
diff --git a/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/old.dbscheme b/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/old.dbscheme
new file mode 100644
index 00000000000..cf21dd4151d
--- /dev/null
+++ b/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/old.dbscheme
@@ -0,0 +1,1890 @@
+
+/**
+ * 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,
+ string queryPath: string ref,
+ int location: @location ref,
+ string message: string ref,
+ float severity: float ref);
+
+externalMetrics(
+ unique int id: @externalMetric,
+ string queryPath: string ref,
+ int location: @location ref,
+ float value: float ref);
+
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+snapshotDate(
+ unique date snapshotDate: date ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Duplicate code
+ */
+
+duplicateCode(
+ unique int id: @duplication,
+ string relativePath: string ref,
+ int equivClass: int ref);
+
+similarCode(
+ unique int id: @similarity,
+ string 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);
+
+/*
+ * 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 | @namespace;
+
+@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(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+/*
+ fromSource(0) = unknown,
+ fromSource(1) = from source,
+ fromSource(2) = from library
+*/
+files(
+ unique int id: @file,
+ string name: string ref,
+ string simple: string ref,
+ string ext: string ref,
+ int fromSource: int ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref,
+ string 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,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_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,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+ ;
+
+@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,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+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: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int 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);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+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);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function;
+
+modifiers(
+ unique int id: @modifier,
+ string 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,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ unique int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, 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
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_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 | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr;
+@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,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
+
+/* 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,
+ string 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,
+ string 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,
+ string 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,
+ string 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,
+ string name: string ref,
+ int property_type: @cil_type ref);
+
+#keyset[parent, name]
+cil_event(unique int id: @cil_event,
+ int parent: @cil_type ref,
+ string 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,
+ string param: string ref,
+ string value: string ref);
+
+#keyset[attribute_id, index]
+cil_attribute_positional_argument(
+ int attribute_id: @cil_attribute ref,
+ int index: int ref,
+ string 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/cf21dd4151d107ab649a2a218e7f52e355c43906/semmlecode.csharp.dbscheme b/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/semmlecode.csharp.dbscheme
new file mode 100644
index 00000000000..ad622770b3c
--- /dev/null
+++ b/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/semmlecode.csharp.dbscheme
@@ -0,0 +1,1893 @@
+
+/**
+ * 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,
+ string queryPath: string ref,
+ int location: @location ref,
+ string message: string ref,
+ float severity: float ref);
+
+externalMetrics(
+ unique int id: @externalMetric,
+ string queryPath: string ref,
+ int location: @location ref,
+ float value: float ref);
+
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+snapshotDate(
+ unique date snapshotDate: date ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Duplicate code
+ */
+
+duplicateCode(
+ unique int id: @duplication,
+ string relativePath: string ref,
+ int equivClass: int ref);
+
+similarCode(
+ unique int id: @similarity,
+ string 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);
+
+/*
+ * 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 | @namespace;
+
+@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(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+/*
+ fromSource(0) = unknown,
+ fromSource(1) = from source,
+ fromSource(2) = from library
+*/
+files(
+ unique int id: @file,
+ string name: string ref,
+ string simple: string ref,
+ string ext: string ref,
+ int fromSource: int ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref,
+ string 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,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_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,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+ ;
+
+@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,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+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: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int 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);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+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);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function;
+
+modifiers(
+ unique int id: @modifier,
+ string 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,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ unique int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, 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
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_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 | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr;
+@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);
+
+stackalloc_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,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
+
+/* 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,
+ string 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,
+ string 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,
+ string 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,
+ string 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,
+ string name: string ref,
+ int property_type: @cil_type ref);
+
+#keyset[parent, name]
+cil_event(unique int id: @cil_event,
+ int parent: @cil_type ref,
+ string 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,
+ string param: string ref,
+ string value: string ref);
+
+#keyset[attribute_id, index]
+cil_attribute_positional_argument(
+ int attribute_id: @cil_attribute ref,
+ int index: int ref,
+ string 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/cf21dd4151d107ab649a2a218e7f52e355c43906/upgrade.properties b/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/upgrade.properties
new file mode 100644
index 00000000000..cc8337a2d1c
--- /dev/null
+++ b/csharp/upgrades/cf21dd4151d107ab649a2a218e7f52e355c43906/upgrade.properties
@@ -0,0 +1,2 @@
+description: Adds information about `stackalloc` array creations
+compatibility: backwards
\ No newline at end of file
diff --git a/docs/language/learn-ql/java/dataflow.rst b/docs/language/learn-ql/java/dataflow.rst
index bddc206aa82..98b8b97e153 100644
--- a/docs/language/learn-ql/java/dataflow.rst
+++ b/docs/language/learn-ql/java/dataflow.rst
@@ -113,7 +113,7 @@ Then we can make the source more specific, for example an access to a public par
where
fileReader.getDeclaringType().hasQualifiedName("java.io", "FileReader") and
call.getCallee() = fileReader and
- DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(fc.getArgument(0)))
+ DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(call.getArgument(0)))
select p
The following example finds calls to formatting functions where the format string is not hard-coded.
diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll
index 767b3d0d25b..e4997154cbc 100644
--- a/python/ql/src/semmle/python/web/bottle/Request.qll
+++ b/python/ql/src/semmle/python/web/bottle/Request.qll
@@ -21,7 +21,7 @@ class BottleRequestKind extends TaintKind {
}
}
-private class RequestSource extends TaintSource {
+private class RequestSource extends HttpRequestTaintSource {
RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) }
override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind }
@@ -69,7 +69,7 @@ class UntrustedFile extends TaintKind {
// Move UntrustedFile to shared location
//
/** Parameter to a bottle request handler function */
-class BottleRequestParameter extends TaintSource {
+class BottleRequestParameter extends HttpRequestTaintSource {
BottleRequestParameter() {
exists(BottleRoute route | route.getNamedArgument() = this.(ControlFlowNode).getNode())
}
diff --git a/python/ql/src/semmle/python/web/cherrypy/Request.qll b/python/ql/src/semmle/python/web/cherrypy/Request.qll
index 2ae897a7f29..2440a2710f6 100644
--- a/python/ql/src/semmle/python/web/cherrypy/Request.qll
+++ b/python/ql/src/semmle/python/web/cherrypy/Request.qll
@@ -25,7 +25,7 @@ class CherryPyRequest extends TaintKind {
}
}
-class CherryPyExposedFunctionParameter extends TaintSource {
+class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
CherryPyExposedFunctionParameter() {
exists(Parameter p |
p = any(CherryPyExposedFunction f).getAnArg() and
@@ -39,7 +39,7 @@ class CherryPyExposedFunctionParameter extends TaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
}
-class CherryPyRequestSource extends TaintSource {
+class CherryPyRequestSource extends HttpRequestTaintSource {
CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) }
override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest }
diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll
index 21995daa024..a810d481a8b 100644
--- a/python/ql/src/semmle/python/web/django/Response.qll
+++ b/python/ql/src/semmle/python/web/django/Response.qll
@@ -18,8 +18,8 @@ private ClassValue theDjangoHttpResponseClass() {
not result = theDjangoHttpRedirectClass()
}
-/** Instantiation of a django response. */
-class DjangoResponseSource extends TaintSource {
+/** internal class used for tracking a django response. */
+private class DjangoResponseSource extends TaintSource {
DjangoResponseSource() {
exists(ClassValue cls |
cls.getASuperType() = theDjangoHttpResponseClass() and
diff --git a/python/ql/src/semmle/python/web/falcon/Request.qll b/python/ql/src/semmle/python/web/falcon/Request.qll
index 2df10d1afc4..13f3fa4c441 100644
--- a/python/ql/src/semmle/python/web/falcon/Request.qll
+++ b/python/ql/src/semmle/python/web/falcon/Request.qll
@@ -35,7 +35,7 @@ class FalconRequest extends TaintKind {
}
}
-class FalconRequestParameter extends TaintSource {
+class FalconRequestParameter extends HttpRequestTaintSource {
FalconRequestParameter() {
exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode())
}
diff --git a/python/ql/src/semmle/python/web/falcon/Response.qll b/python/ql/src/semmle/python/web/falcon/Response.qll
index 8eff15dd53c..ab7798cc2cb 100644
--- a/python/ql/src/semmle/python/web/falcon/Response.qll
+++ b/python/ql/src/semmle/python/web/falcon/Response.qll
@@ -9,7 +9,8 @@ class FalconResponse extends TaintKind {
FalconResponse() { this = "falcon.response" }
}
-class FalconResponseParameter extends TaintSource {
+/** Only used internally to track the response parameter */
+private class FalconResponseParameter extends TaintSource {
FalconResponseParameter() {
exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode())
}
diff --git a/python/ql/src/semmle/python/web/flask/Request.qll b/python/ql/src/semmle/python/web/flask/Request.qll
index e27e54c722f..8dbc3a5ba42 100644
--- a/python/ql/src/semmle/python/web/flask/Request.qll
+++ b/python/ql/src/semmle/python/web/flask/Request.qll
@@ -47,7 +47,7 @@ class FlaskRequestArgs extends HttpRequestTaintSource {
}
/** Source of dictionary whose values are externally controlled */
-class FlaskRequestJson extends TaintSource {
+class FlaskRequestJson extends HttpRequestTaintSource {
FlaskRequestJson() { flask_request_attr(this, "json") }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind }
diff --git a/python/ql/src/semmle/python/web/pyramid/Request.qll b/python/ql/src/semmle/python/web/pyramid/Request.qll
index 2514e77d5ac..dc5be31e68a 100644
--- a/python/ql/src/semmle/python/web/pyramid/Request.qll
+++ b/python/ql/src/semmle/python/web/pyramid/Request.qll
@@ -11,7 +11,7 @@ class PyramidRequest extends BaseWebobRequest {
}
/** Source of pyramid request objects */
-class PyramidViewArgument extends TaintSource {
+class PyramidViewArgument extends HttpRequestTaintSource {
PyramidViewArgument() {
exists(Function view_func |
is_pyramid_view_function(view_func) and
diff --git a/python/ql/src/semmle/python/web/tornado/Redirect.qll b/python/ql/src/semmle/python/web/tornado/Redirect.qll
index cf213a5b044..2d2c39907eb 100644
--- a/python/ql/src/semmle/python/web/tornado/Redirect.qll
+++ b/python/ql/src/semmle/python/web/tornado/Redirect.qll
@@ -13,14 +13,16 @@ import Tornado
/**
* Represents an argument to the `tornado.redirect` function.
*/
-class TornadoRedirect extends HttpRedirectTaintSink {
- override string toString() { result = "tornado.redirect" }
+class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
+ override string toString() { result = "tornado.HttpRequestHandler.redirect" }
- TornadoRedirect() {
+ TornadoHttpRequestHandlerRedirect() {
exists(CallNode call, ControlFlowNode node |
node = call.getFunction().(AttrNode).getObject("redirect") and
isTornadoRequestHandlerInstance(node) and
- this = call.getAnArg()
+ this = call.getArg(0)
)
}
+
+ override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
diff --git a/python/ql/src/semmle/python/web/tornado/Request.qll b/python/ql/src/semmle/python/web/tornado/Request.qll
index a5a6c752f8e..66c77d4f269 100644
--- a/python/ql/src/semmle/python/web/tornado/Request.qll
+++ b/python/ql/src/semmle/python/web/tornado/Request.qll
@@ -30,7 +30,7 @@ class TornadoRequest extends TaintKind {
}
}
-class TornadoRequestSource extends TaintSource {
+class TornadoRequestSource extends HttpRequestTaintSource {
TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) }
override string toString() { result = "Tornado request source" }
@@ -38,7 +38,7 @@ class TornadoRequestSource extends TaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest }
}
-class TornadoExternalInputSource extends TaintSource {
+class TornadoExternalInputSource extends HttpRequestTaintSource {
TornadoExternalInputSource() {
exists(string name |
name = "get_argument" or
@@ -55,7 +55,7 @@ class TornadoExternalInputSource extends TaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
}
-class TornadoExternalInputListSource extends TaintSource {
+class TornadoExternalInputListSource extends HttpRequestTaintSource {
TornadoExternalInputListSource() {
exists(string name |
name = "get_arguments" or
diff --git a/python/ql/src/semmle/python/web/tornado/Response.qll b/python/ql/src/semmle/python/web/tornado/Response.qll
index e6312c49549..2c2da1a4c70 100644
--- a/python/ql/src/semmle/python/web/tornado/Response.qll
+++ b/python/ql/src/semmle/python/web/tornado/Response.qll
@@ -24,11 +24,8 @@ class TornadoConnectionWrite extends HttpResponseTaintSink {
TornadoConnectionWrite() {
exists(CallNode call, ControlFlowNode conn |
conn = call.getFunction().(AttrNode).getObject("write") and
- this = call.getAnArg()
- |
+ this = call.getAnArg() and
exists(TornadoConnection tc | tc.taints(conn))
- or
- isTornadoRequestHandlerInstance(conn)
)
}
@@ -36,27 +33,13 @@ class TornadoConnectionWrite extends HttpResponseTaintSink {
}
class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
- override string toString() { result = "tornado.HttpRequesHandler.write" }
+ override string toString() { result = "tornado.HttpRequestHandler.write" }
TornadoHttpRequestHandlerWrite() {
exists(CallNode call, ControlFlowNode node |
node = call.getFunction().(AttrNode).getObject("write") and
- isTornadoRequestHandlerInstance(node) and
- this = call.getAnArg()
- )
- }
-
- override predicate sinks(TaintKind kind) { kind instanceof StringKind }
-}
-
-class TornadoHttpRequestHandlerRedirect extends HttpResponseTaintSink {
- override string toString() { result = "tornado.HttpRequesHandler.redirect" }
-
- TornadoHttpRequestHandlerRedirect() {
- exists(CallNode call, ControlFlowNode node |
- node = call.getFunction().(AttrNode).getObject("redirect") and
- isTornadoRequestHandlerInstance(node) and
- this = call.getArg(0)
+ this = call.getAnArg() and
+ isTornadoRequestHandlerInstance(node)
)
}
diff --git a/python/ql/src/semmle/python/web/turbogears/Request.qll b/python/ql/src/semmle/python/web/turbogears/Request.qll
index dc7ef63ab56..92d5728b91f 100644
--- a/python/ql/src/semmle/python/web/turbogears/Request.qll
+++ b/python/ql/src/semmle/python/web/turbogears/Request.qll
@@ -1,5 +1,6 @@
import python
import semmle.python.security.strings.Untrusted
+import semmle.python.web.Http
import TurboGears
private class ValidatedMethodParameter extends Parameter {
@@ -11,7 +12,7 @@ private class ValidatedMethodParameter extends Parameter {
}
}
-class UnvalidatedControllerMethodParameter extends TaintSource {
+class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
UnvalidatedControllerMethodParameter() {
exists(Parameter p |
any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and
diff --git a/python/ql/src/semmle/python/web/turbogears/Response.qll b/python/ql/src/semmle/python/web/turbogears/Response.qll
index ddd3d6f711f..cab083bf8b7 100644
--- a/python/ql/src/semmle/python/web/turbogears/Response.qll
+++ b/python/ql/src/semmle/python/web/turbogears/Response.qll
@@ -5,6 +5,8 @@ import semmle.python.web.Http
import TurboGears
class ControllerMethodReturnValue extends HttpResponseTaintSink {
+ override string toString() { result = "TurboGears ControllerMethodReturnValue" }
+
ControllerMethodReturnValue() {
exists(TurboGearsControllerMethod m |
m.getAReturnValueFlowNode() = this and
@@ -16,6 +18,8 @@ class ControllerMethodReturnValue extends HttpResponseTaintSink {
}
class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
+ override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" }
+
ControllerMethodTemplatedReturnValue() {
exists(TurboGearsControllerMethod m |
m.getAReturnValueFlowNode() = this and
diff --git a/python/ql/src/semmle/python/web/twisted/Request.qll b/python/ql/src/semmle/python/web/twisted/Request.qll
index 67bb8cedbfe..969392d0eef 100644
--- a/python/ql/src/semmle/python/web/twisted/Request.qll
+++ b/python/ql/src/semmle/python/web/twisted/Request.qll
@@ -26,7 +26,7 @@ class TwistedRequest extends TaintKind {
}
}
-class TwistedRequestSource extends TaintSource {
+class TwistedRequestSource extends HttpRequestTaintSource {
TwistedRequestSource() { isTwistedRequestInstance(this) }
override string toString() { result = "Twisted request source" }
diff --git a/python/ql/src/semmle/python/web/twisted/Response.qll b/python/ql/src/semmle/python/web/twisted/Response.qll
index 435960c40ab..b7f67ff6b20 100644
--- a/python/ql/src/semmle/python/web/twisted/Response.qll
+++ b/python/ql/src/semmle/python/web/twisted/Response.qll
@@ -5,9 +5,9 @@ import semmle.python.security.strings.Basic
import Twisted
import Request
-class TwistedResponse extends TaintSink {
+class TwistedResponse extends HttpResponseTaintSink {
TwistedResponse() {
- exists(PythonFunctionValue func, string name, Return ret |
+ exists(PythonFunctionValue func, string name |
isKnownRequestHandlerMethodName(name) and
name = func.getName() and
func = getTwistedRequestHandlerMethod(name) and
diff --git a/python/ql/test/2/library-tests/six/options b/python/ql/test/2/library-tests/six/options
index 8a2bd0171db..55e896b67f2 100644
--- a/python/ql/test/2/library-tests/six/options
+++ b/python/ql/test/2/library-tests/six/options
@@ -1,2 +1,2 @@
-semmle-extractor-options: --lang=2 --max-import-depth=3
+semmle-extractor-options: --lang=2 --max-import-depth=4
optimize: true
diff --git a/python/ql/test/2/library-tests/six/pointsto.expected b/python/ql/test/2/library-tests/six/pointsto.expected
index 7b475d40eb7..0e0d568caf3 100644
--- a/python/ql/test/2/library-tests/six/pointsto.expected
+++ b/python/ql/test/2/library-tests/six/pointsto.expected
@@ -1,3 +1,9 @@
-| six | Module six |
-| six.moves | Module six.moves |
+| six | Package six |
+| six.moves | Package six.moves |
+| six.moves.http_client | Module httplib |
+| six.moves.http_client.HTTPConnection | class HTTPConnection |
| six.moves.range | builtin-class xrange |
+| six.moves.urllib | Package six.moves.urllib |
+| six.moves.urllib.parse | Module six.moves.urllib_parse |
+| six.moves.urllib.parse.urlsplit | Function urlsplit |
+| six.moves.zip | builtin-class itertools.izip |
diff --git a/python/ql/test/2/library-tests/six/pointsto.ql b/python/ql/test/2/library-tests/six/pointsto.ql
index 8104a2e6628..d44761b1b12 100644
--- a/python/ql/test/2/library-tests/six/pointsto.ql
+++ b/python/ql/test/2/library-tests/six/pointsto.ql
@@ -1,15 +1,11 @@
-
import python
string longname(Expr e) {
result = e.(Name).getId()
or
- exists(Attribute a |
- a = e |
- result = longname(a.getObject()) + "." + a.getName()
- )
+ exists(Attribute a | a = e | result = longname(a.getObject()) + "." + a.getName())
}
-from Expr e, Object o
-where e.refersTo(o) and e.getLocation().getFile().getShortName() = "test.py"
-select longname(e), o.toString()
\ No newline at end of file
+from Expr e, Value v
+where e.pointsTo(v) and e.getLocation().getFile().getShortName() = "test.py"
+select longname(e), v.toString()
diff --git a/python/ql/test/2/library-tests/six/test.expected b/python/ql/test/2/library-tests/six/test.expected
deleted file mode 100644
index 50ad5bc7e57..00000000000
--- a/python/ql/test/2/library-tests/six/test.expected
+++ /dev/null
@@ -1,268 +0,0 @@
-| Module six | BytesIO | class StringIO |
-| Module six | Iterator | class Iterator |
-| Module six | MAXSIZE | int() |
-| Module six | PY2 | bool True |
-| Module six | PY3 | bool False |
-| Module six | StringIO | class StringIO |
-| Module six | __author__ | str b'Benjamin Peterson ' |
-| Module six | __name__ | str b'six' |
-| Module six | __version__ | str b'1.5.2' |
-| Module six | _add_doc | Function _add_doc |
-| Module six | _func_closure | str b'func_closure' |
-| Module six | _func_code | str b'func_code' |
-| Module six | _func_defaults | str b'func_defaults' |
-| Module six | _func_globals | str b'func_globals' |
-| Module six | _import_module | Function _import_module |
-| Module six | _iteritems | str b'iteritems' |
-| Module six | _iterkeys | str b'iterkeys' |
-| Module six | _iterlists | str b'iterlists' |
-| Module six | _itervalues | str b'itervalues' |
-| Module six | _meth_func | str b'im_func' |
-| Module six | _meth_self | str b'im_self' |
-| Module six | add_metaclass | Function add_metaclass |
-| Module six | add_move | Function add_move |
-| Module six | advance_iterator | Builtin-function next |
-| Module six | b | Function b |
-| Module six | binary_type | builtin-class str |
-| Module six | byte2int | Function byte2int |
-| Module six | callable | Builtin-function callable |
-| Module six | callable | Function callable |
-| Module six | class_types | Tuple |
-| Module six | create_bound_method | Function create_bound_method |
-| Module six | exec_ | Function exec_ |
-| Module six | get_function_closure | Attribute() |
-| Module six | get_function_code | Attribute() |
-| Module six | get_function_defaults | Attribute() |
-| Module six | get_function_globals | Attribute() |
-| Module six | get_method_function | Attribute() |
-| Module six | get_method_self | Attribute() |
-| Module six | get_unbound_function | Function get_unbound_function |
-| Module six | indexbytes | Function indexbytes |
-| Module six | int2byte | Builtin-function chr |
-| Module six | integer_types | Tuple |
-| Module six | iterbytes | Function iterbytes |
-| Module six | iteritems | Function iteritems |
-| Module six | iterkeys | Function iterkeys |
-| Module six | iterlists | Function iterlists |
-| Module six | itervalues | Function itervalues |
-| Module six | moves | Module six.moves |
-| Module six | next | Builtin-function next |
-| Module six | operator | Module operator |
-| Module six | print_ | Function print_ |
-| Module six | remove_move | Function remove_move |
-| Module six | reraise | Function reraise |
-| Module six | string_types | Tuple |
-| Module six | sys | Module sys |
-| Module six | text_type | builtin-class unicode |
-| Module six | types | Module types |
-| Module six | u | Function u |
-| Module six | unichr | Builtin-function unichr |
-| Module six | with_metaclass | Function with_metaclass |
-| Module six.__init__ | BytesIO | class StringIO |
-| Module six.__init__ | Iterator | class Iterator |
-| Module six.__init__ | MAXSIZE | int() |
-| Module six.__init__ | PY2 | bool True |
-| Module six.__init__ | PY3 | bool False |
-| Module six.__init__ | StringIO | class StringIO |
-| Module six.__init__ | __author__ | str b'Benjamin Peterson ' |
-| Module six.__init__ | __name__ | str b'six' |
-| Module six.__init__ | __version__ | str b'1.5.2' |
-| Module six.__init__ | _add_doc | Function _add_doc |
-| Module six.__init__ | _func_closure | str b'func_closure' |
-| Module six.__init__ | _func_code | str b'func_code' |
-| Module six.__init__ | _func_defaults | str b'func_defaults' |
-| Module six.__init__ | _func_globals | str b'func_globals' |
-| Module six.__init__ | _import_module | Function _import_module |
-| Module six.__init__ | _iteritems | str b'iteritems' |
-| Module six.__init__ | _iterkeys | str b'iterkeys' |
-| Module six.__init__ | _iterlists | str b'iterlists' |
-| Module six.__init__ | _itervalues | str b'itervalues' |
-| Module six.__init__ | _meth_func | str b'im_func' |
-| Module six.__init__ | _meth_self | str b'im_self' |
-| Module six.__init__ | add_metaclass | Function add_metaclass |
-| Module six.__init__ | add_move | Function add_move |
-| Module six.__init__ | advance_iterator | Builtin-function next |
-| Module six.__init__ | b | Function b |
-| Module six.__init__ | binary_type | builtin-class str |
-| Module six.__init__ | byte2int | Function byte2int |
-| Module six.__init__ | callable | Builtin-function callable |
-| Module six.__init__ | callable | Function callable |
-| Module six.__init__ | class_types | Tuple |
-| Module six.__init__ | create_bound_method | Function create_bound_method |
-| Module six.__init__ | exec_ | Function exec_ |
-| Module six.__init__ | get_function_closure | Attribute() |
-| Module six.__init__ | get_function_code | Attribute() |
-| Module six.__init__ | get_function_defaults | Attribute() |
-| Module six.__init__ | get_function_globals | Attribute() |
-| Module six.__init__ | get_method_function | Attribute() |
-| Module six.__init__ | get_method_self | Attribute() |
-| Module six.__init__ | get_unbound_function | Function get_unbound_function |
-| Module six.__init__ | indexbytes | Function indexbytes |
-| Module six.__init__ | int2byte | Builtin-function chr |
-| Module six.__init__ | integer_types | Tuple |
-| Module six.__init__ | iterbytes | Function iterbytes |
-| Module six.__init__ | iteritems | Function iteritems |
-| Module six.__init__ | iterkeys | Function iterkeys |
-| Module six.__init__ | iterlists | Function iterlists |
-| Module six.__init__ | itervalues | Function itervalues |
-| Module six.__init__ | moves | Module six.moves |
-| Module six.__init__ | next | Builtin-function next |
-| Module six.__init__ | operator | Module operator |
-| Module six.__init__ | print_ | Function print_ |
-| Module six.__init__ | remove_move | Function remove_move |
-| Module six.__init__ | reraise | Function reraise |
-| Module six.__init__ | string_types | Tuple |
-| Module six.__init__ | sys | Module sys |
-| Module six.__init__ | text_type | builtin-class unicode |
-| Module six.__init__ | types | Module types |
-| Module six.__init__ | u | Function u |
-| Module six.__init__ | unichr | Builtin-function unichr |
-| Module six.__init__ | with_metaclass | Function with_metaclass |
-| Module six.moves | BaseHTTPServer | Module BaseHTTPServer |
-| Module six.moves | CGIHTTPServer | Module CGIHTTPServer |
-| Module six.moves | PY2 | bool True |
-| Module six.moves | PY3 | bool False |
-| Module six.moves | SimpleHTTPServer | Module SimpleHTTPServer |
-| Module six.moves | StringIO | class StringIO |
-| Module six.moves | UserDict | class UserDict |
-| Module six.moves | UserList | class UserList |
-| Module six.moves | UserString | class UserString |
-| Module six.moves | __name__ | str b'six.moves' |
-| Module six.moves | _dummy_thread | Module dummy_thread |
-| Module six.moves | _thread | Module thread |
-| Module six.moves | builtins | Module __builtin__ |
-| Module six.moves | cPickle | Module cPickle |
-| Module six.moves | cStringIO | Builtin-function StringIO |
-| Module six.moves | configparser | Module ConfigParser |
-| Module six.moves | copyreg | Module copy_reg |
-| Module six.moves | filter | builtin-class itertools.ifilter |
-| Module six.moves | filterfalse | builtin-class itertools.ifilterfalse |
-| Module six.moves | html_entities | Module htmlentitydefs |
-| Module six.moves | html_parser | Module HTMLParser |
-| Module six.moves | http_client | Module httplib |
-| Module six.moves | http_cookiejar | Module cookielib |
-| Module six.moves | http_cookies | Module Cookie |
-| Module six.moves | input | Builtin-function raw_input |
-| Module six.moves | intern | Builtin-function intern |
-| Module six.moves | map | builtin-class itertools.imap |
-| Module six.moves | queue | Module Queue |
-| Module six.moves | range | builtin-class xrange |
-| Module six.moves | reduce | Builtin-function reduce |
-| Module six.moves | reload_module | Builtin-function reload |
-| Module six.moves | reprlib | Module repr |
-| Module six.moves | shlex_quote | Function quote |
-| Module six.moves | socketserver | Module SocketServer |
-| Module six.moves | tkinter | Module Tkinter |
-| Module six.moves | tkinter_colorchooser | Module tkColorChooser |
-| Module six.moves | tkinter_commondialog | Module tkCommonDialog |
-| Module six.moves | tkinter_constants | Module Tkconstants |
-| Module six.moves | tkinter_dialog | Module Dialog |
-| Module six.moves | tkinter_dnd | Module Tkdnd |
-| Module six.moves | tkinter_filedialog | Module FileDialog |
-| Module six.moves | tkinter_font | Module tkFont |
-| Module six.moves | tkinter_messagebox | Module tkMessageBox |
-| Module six.moves | tkinter_scrolledtext | Module ScrolledText |
-| Module six.moves | tkinter_simpledialog | Module SimpleDialog |
-| Module six.moves | tkinter_tix | Module Tix |
-| Module six.moves | tkinter_tkfiledialog | Module tkFileDialog |
-| Module six.moves | tkinter_tksimpledialog | Module tkSimpleDialog |
-| Module six.moves | tkinter_ttk | Module ttk |
-| Module six.moves | urllib | Module six.moves.urllib |
-| Module six.moves | urllib_error | Module six.moves.urllib_error |
-| Module six.moves | urllib_parse | Module six.moves.urllib_parse |
-| Module six.moves | urllib_request | Module six.moves.urllib_request |
-| Module six.moves | urllib_response | Module six.moves.urllib_response |
-| Module six.moves | urllib_robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves | xmlrpc_client | Module xmlrpclib |
-| Module six.moves | xmlrpc_server | Module SimpleXMLRPCServer |
-| Module six.moves | xrange | builtin-class xrange |
-| Module six.moves | zip | builtin-class itertools.izip |
-| Module six.moves | zip_longest | builtin-class itertools.izip_longest |
-| Module six.moves.__init__ | BaseHTTPServer | Module BaseHTTPServer |
-| Module six.moves.__init__ | CGIHTTPServer | Module CGIHTTPServer |
-| Module six.moves.__init__ | PY2 | bool True |
-| Module six.moves.__init__ | PY3 | bool False |
-| Module six.moves.__init__ | SimpleHTTPServer | Module SimpleHTTPServer |
-| Module six.moves.__init__ | StringIO | class StringIO |
-| Module six.moves.__init__ | UserDict | class UserDict |
-| Module six.moves.__init__ | UserList | class UserList |
-| Module six.moves.__init__ | UserString | class UserString |
-| Module six.moves.__init__ | __name__ | str b'six.moves' |
-| Module six.moves.__init__ | _dummy_thread | Module dummy_thread |
-| Module six.moves.__init__ | _thread | Module thread |
-| Module six.moves.__init__ | builtins | Module __builtin__ |
-| Module six.moves.__init__ | cPickle | Module cPickle |
-| Module six.moves.__init__ | cStringIO | Builtin-function StringIO |
-| Module six.moves.__init__ | configparser | Module ConfigParser |
-| Module six.moves.__init__ | copyreg | Module copy_reg |
-| Module six.moves.__init__ | filter | builtin-class itertools.ifilter |
-| Module six.moves.__init__ | filterfalse | builtin-class itertools.ifilterfalse |
-| Module six.moves.__init__ | html_entities | Module htmlentitydefs |
-| Module six.moves.__init__ | html_parser | Module HTMLParser |
-| Module six.moves.__init__ | http_client | Module httplib |
-| Module six.moves.__init__ | http_cookiejar | Module cookielib |
-| Module six.moves.__init__ | http_cookies | Module Cookie |
-| Module six.moves.__init__ | input | Builtin-function raw_input |
-| Module six.moves.__init__ | intern | Builtin-function intern |
-| Module six.moves.__init__ | map | builtin-class itertools.imap |
-| Module six.moves.__init__ | queue | Module Queue |
-| Module six.moves.__init__ | range | builtin-class xrange |
-| Module six.moves.__init__ | reduce | Builtin-function reduce |
-| Module six.moves.__init__ | reload_module | Builtin-function reload |
-| Module six.moves.__init__ | reprlib | Module repr |
-| Module six.moves.__init__ | shlex_quote | Function quote |
-| Module six.moves.__init__ | socketserver | Module SocketServer |
-| Module six.moves.__init__ | tkinter | Module Tkinter |
-| Module six.moves.__init__ | tkinter_colorchooser | Module tkColorChooser |
-| Module six.moves.__init__ | tkinter_commondialog | Module tkCommonDialog |
-| Module six.moves.__init__ | tkinter_constants | Module Tkconstants |
-| Module six.moves.__init__ | tkinter_dialog | Module Dialog |
-| Module six.moves.__init__ | tkinter_dnd | Module Tkdnd |
-| Module six.moves.__init__ | tkinter_filedialog | Module FileDialog |
-| Module six.moves.__init__ | tkinter_font | Module tkFont |
-| Module six.moves.__init__ | tkinter_messagebox | Module tkMessageBox |
-| Module six.moves.__init__ | tkinter_scrolledtext | Module ScrolledText |
-| Module six.moves.__init__ | tkinter_simpledialog | Module SimpleDialog |
-| Module six.moves.__init__ | tkinter_tix | Module Tix |
-| Module six.moves.__init__ | tkinter_tkfiledialog | Module tkFileDialog |
-| Module six.moves.__init__ | tkinter_tksimpledialog | Module tkSimpleDialog |
-| Module six.moves.__init__ | tkinter_ttk | Module ttk |
-| Module six.moves.__init__ | urllib | Module six.moves.urllib |
-| Module six.moves.__init__ | urllib_error | Module six.moves.urllib_error |
-| Module six.moves.__init__ | urllib_parse | Module six.moves.urllib_parse |
-| Module six.moves.__init__ | urllib_request | Module six.moves.urllib_request |
-| Module six.moves.__init__ | urllib_response | Module six.moves.urllib_response |
-| Module six.moves.__init__ | urllib_robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves.__init__ | xmlrpc_client | Module xmlrpclib |
-| Module six.moves.__init__ | xmlrpc_server | Module SimpleXMLRPCServer |
-| Module six.moves.__init__ | xrange | builtin-class xrange |
-| Module six.moves.__init__ | zip | builtin-class itertools.izip |
-| Module six.moves.__init__ | zip_longest | builtin-class itertools.izip_longest |
-| Module six.moves.urllib | __name__ | str b'six.moves.urllib' |
-| Module six.moves.urllib | error | Module six.moves.urllib_error |
-| Module six.moves.urllib | parse | Module six.moves.urllib_parse |
-| Module six.moves.urllib | request | Module six.moves.urllib_request |
-| Module six.moves.urllib | response | Module six.moves.urllib_response |
-| Module six.moves.urllib | robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves.urllib.__init__ | __name__ | str b'six.moves.urllib' |
-| Module six.moves.urllib.__init__ | error | Module six.moves.urllib_error |
-| Module six.moves.urllib.__init__ | parse | Module six.moves.urllib_parse |
-| Module six.moves.urllib.__init__ | request | Module six.moves.urllib_request |
-| Module six.moves.urllib.__init__ | response | Module six.moves.urllib_response |
-| Module six.moves.urllib.__init__ | robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves.urllib_error | PY2 | bool True |
-| Module six.moves.urllib_error | PY3 | bool False |
-| Module six.moves.urllib_error | __name__ | str b'six.moves.urllib_error' |
-| Module six.moves.urllib_parse | PY2 | bool True |
-| Module six.moves.urllib_parse | PY3 | bool False |
-| Module six.moves.urllib_parse | __name__ | str b'six.moves.urllib_parse' |
-| Module six.moves.urllib_request | PY2 | bool True |
-| Module six.moves.urllib_request | PY3 | bool False |
-| Module six.moves.urllib_request | __name__ | str b'six.moves.urllib_request' |
-| Module six.moves.urllib_response | PY2 | bool True |
-| Module six.moves.urllib_response | PY3 | bool False |
-| Module six.moves.urllib_response | __name__ | str b'six.moves.urllib_response' |
-| Module six.moves.urllib_robotparser | PY2 | bool True |
-| Module six.moves.urllib_robotparser | PY3 | bool False |
-| Module six.moves.urllib_robotparser | RobotFileParser | class RobotFileParser |
-| Module six.moves.urllib_robotparser | __name__ | str b'six.moves.urllib_robotparser' |
diff --git a/python/ql/test/2/library-tests/six/test.py b/python/ql/test/2/library-tests/six/test.py
index ff8b9f33bb5..cac31dceb8a 100644
--- a/python/ql/test/2/library-tests/six/test.py
+++ b/python/ql/test/2/library-tests/six/test.py
@@ -1,5 +1,9 @@
import six
-#Check that some expected attributes are visible
+# Check that some expected attributes are visible -- this is the reason we added stubs in
+# the first place! If this works, we're happy!
six.moves
six.moves.range
+six.moves.zip
+six.moves.http_client.HTTPConnection
+six.moves.urllib.parse.urlsplit
diff --git a/python/ql/test/2/library-tests/six/test.ql b/python/ql/test/2/library-tests/six/test.ql
deleted file mode 100644
index 5d694b9fec9..00000000000
--- a/python/ql/test/2/library-tests/six/test.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-import python
-
-predicate six(ModuleObject m) {
- m.getName() = "six"
- or
- six(m.getPackage())
-}
-
-from ModuleObject mod, string name, Object obj
-where mod.attributeRefersTo(name, obj, _) and six(mod)
-select mod.toString(), name, obj.toString()
diff --git a/python/ql/test/3/library-tests/six/options b/python/ql/test/3/library-tests/six/options
index be048160aeb..8e16f310b52 100644
--- a/python/ql/test/3/library-tests/six/options
+++ b/python/ql/test/3/library-tests/six/options
@@ -1,2 +1,2 @@
-semmle-extractor-options: --max-import-depth=3
+semmle-extractor-options: --max-import-depth=4
optimize: true
diff --git a/python/ql/test/3/library-tests/six/pointsto.expected b/python/ql/test/3/library-tests/six/pointsto.expected
index 64cd745b873..6d1a9181e82 100644
--- a/python/ql/test/3/library-tests/six/pointsto.expected
+++ b/python/ql/test/3/library-tests/six/pointsto.expected
@@ -1,3 +1,9 @@
-| six | Module six |
-| six.moves | Module six.moves |
+| six | Package six |
+| six.moves | Package six.moves |
+| six.moves.http_client | Module http.client |
+| six.moves.http_client.HTTPConnection | class HTTPConnection |
| six.moves.range | builtin-class range |
+| six.moves.urllib | Package six.moves.urllib |
+| six.moves.urllib.parse | Module six.moves.urllib_parse |
+| six.moves.urllib.parse.urlsplit | Function urlsplit |
+| six.moves.zip | builtin-class zip |
diff --git a/python/ql/test/3/library-tests/six/pointsto.ql b/python/ql/test/3/library-tests/six/pointsto.ql
index 486242930b9..d44761b1b12 100644
--- a/python/ql/test/3/library-tests/six/pointsto.ql
+++ b/python/ql/test/3/library-tests/six/pointsto.ql
@@ -1,16 +1,11 @@
-
import python
string longname(Expr e) {
result = e.(Name).getId()
or
- exists(Attribute a |
- a = e |
- result = longname(a.getObject()) + "." + a.getName()
- )
+ exists(Attribute a | a = e | result = longname(a.getObject()) + "." + a.getName())
}
-from Expr e, Object o
-where e.refersTo(o) and e.getLocation().getFile().getShortName() = "test.py"
-select longname(e), o.toString()
-
+from Expr e, Value v
+where e.pointsTo(v) and e.getLocation().getFile().getShortName() = "test.py"
+select longname(e), v.toString()
diff --git a/python/ql/test/3/library-tests/six/test.expected b/python/ql/test/3/library-tests/six/test.expected
deleted file mode 100644
index 199ab676f4f..00000000000
--- a/python/ql/test/3/library-tests/six/test.expected
+++ /dev/null
@@ -1,262 +0,0 @@
-| Module six | BytesIO | builtin-class _io.BytesIO |
-| Module six | Iterator | builtin-class object |
-| Module six | MAXSIZE | int 9223372036854775807 |
-| Module six | PY2 | bool False |
-| Module six | PY3 | bool True |
-| Module six | StringIO | builtin-class _io.StringIO |
-| Module six | __author__ | str u'Benjamin Peterson ' |
-| Module six | __name__ | str u'six' |
-| Module six | __version__ | str u'1.5.2' |
-| Module six | _add_doc | Function _add_doc |
-| Module six | _func_closure | str u'__closure__' |
-| Module six | _func_code | str u'__code__' |
-| Module six | _func_defaults | str u'__defaults__' |
-| Module six | _func_globals | str u'__globals__' |
-| Module six | _import_module | Function _import_module |
-| Module six | _iteritems | str u'items' |
-| Module six | _iterkeys | str u'keys' |
-| Module six | _iterlists | str u'lists' |
-| Module six | _itervalues | str u'values' |
-| Module six | _meth_func | str u'__func__' |
-| Module six | _meth_self | str u'__self__' |
-| Module six | add_metaclass | Function add_metaclass |
-| Module six | add_move | Function add_move |
-| Module six | advance_iterator | Builtin-function next |
-| Module six | b | Function b |
-| Module six | binary_type | builtin-class bytes |
-| Module six | byte2int | Function byte2int |
-| Module six | callable | Builtin-function callable |
-| Module six | callable | Function callable |
-| Module six | class_types | Tuple |
-| Module six | create_bound_method | builtin-class method |
-| Module six | get_function_closure | Attribute() |
-| Module six | get_function_code | Attribute() |
-| Module six | get_function_defaults | Attribute() |
-| Module six | get_function_globals | Attribute() |
-| Module six | get_method_function | Attribute() |
-| Module six | get_method_self | Attribute() |
-| Module six | get_unbound_function | Function get_unbound_function |
-| Module six | indexbytes | Builtin-function getitem |
-| Module six | int2byte | Function int2byte |
-| Module six | integer_types | Tuple |
-| Module six | io | Module io |
-| Module six | iterbytes | Builtin-function iter |
-| Module six | iteritems | Function iteritems |
-| Module six | iterkeys | Function iterkeys |
-| Module six | iterlists | Function iterlists |
-| Module six | itervalues | Function itervalues |
-| Module six | moves | Module six.moves |
-| Module six | next | Builtin-function next |
-| Module six | operator | Module operator |
-| Module six | print_ | Function print_ |
-| Module six | remove_move | Function remove_move |
-| Module six | reraise | Function reraise |
-| Module six | string_types | Tuple |
-| Module six | sys | Module sys |
-| Module six | text_type | builtin-class str |
-| Module six | types | Module types |
-| Module six | u | Function u |
-| Module six | unichr | Builtin-function chr |
-| Module six | with_metaclass | Function with_metaclass |
-| Module six.__init__ | BytesIO | builtin-class _io.BytesIO |
-| Module six.__init__ | Iterator | builtin-class object |
-| Module six.__init__ | MAXSIZE | int 9223372036854775807 |
-| Module six.__init__ | PY2 | bool False |
-| Module six.__init__ | PY3 | bool True |
-| Module six.__init__ | StringIO | builtin-class _io.StringIO |
-| Module six.__init__ | __author__ | str u'Benjamin Peterson ' |
-| Module six.__init__ | __name__ | str u'six' |
-| Module six.__init__ | __version__ | str u'1.5.2' |
-| Module six.__init__ | _add_doc | Function _add_doc |
-| Module six.__init__ | _func_closure | str u'__closure__' |
-| Module six.__init__ | _func_code | str u'__code__' |
-| Module six.__init__ | _func_defaults | str u'__defaults__' |
-| Module six.__init__ | _func_globals | str u'__globals__' |
-| Module six.__init__ | _import_module | Function _import_module |
-| Module six.__init__ | _iteritems | str u'items' |
-| Module six.__init__ | _iterkeys | str u'keys' |
-| Module six.__init__ | _iterlists | str u'lists' |
-| Module six.__init__ | _itervalues | str u'values' |
-| Module six.__init__ | _meth_func | str u'__func__' |
-| Module six.__init__ | _meth_self | str u'__self__' |
-| Module six.__init__ | add_metaclass | Function add_metaclass |
-| Module six.__init__ | add_move | Function add_move |
-| Module six.__init__ | advance_iterator | Builtin-function next |
-| Module six.__init__ | b | Function b |
-| Module six.__init__ | binary_type | builtin-class bytes |
-| Module six.__init__ | byte2int | Function byte2int |
-| Module six.__init__ | callable | Builtin-function callable |
-| Module six.__init__ | callable | Function callable |
-| Module six.__init__ | class_types | Tuple |
-| Module six.__init__ | create_bound_method | builtin-class method |
-| Module six.__init__ | get_function_closure | Attribute() |
-| Module six.__init__ | get_function_code | Attribute() |
-| Module six.__init__ | get_function_defaults | Attribute() |
-| Module six.__init__ | get_function_globals | Attribute() |
-| Module six.__init__ | get_method_function | Attribute() |
-| Module six.__init__ | get_method_self | Attribute() |
-| Module six.__init__ | get_unbound_function | Function get_unbound_function |
-| Module six.__init__ | indexbytes | Builtin-function getitem |
-| Module six.__init__ | int2byte | Function int2byte |
-| Module six.__init__ | integer_types | Tuple |
-| Module six.__init__ | io | Module io |
-| Module six.__init__ | iterbytes | Builtin-function iter |
-| Module six.__init__ | iteritems | Function iteritems |
-| Module six.__init__ | iterkeys | Function iterkeys |
-| Module six.__init__ | iterlists | Function iterlists |
-| Module six.__init__ | itervalues | Function itervalues |
-| Module six.__init__ | moves | Module six.moves |
-| Module six.__init__ | next | Builtin-function next |
-| Module six.__init__ | operator | Module operator |
-| Module six.__init__ | print_ | Function print_ |
-| Module six.__init__ | remove_move | Function remove_move |
-| Module six.__init__ | reraise | Function reraise |
-| Module six.__init__ | string_types | Tuple |
-| Module six.__init__ | sys | Module sys |
-| Module six.__init__ | text_type | builtin-class str |
-| Module six.__init__ | types | Module types |
-| Module six.__init__ | u | Function u |
-| Module six.__init__ | unichr | Builtin-function chr |
-| Module six.__init__ | with_metaclass | Function with_metaclass |
-| Module six.moves | BaseHTTPServer | Module http.server |
-| Module six.moves | CGIHTTPServer | Module http.server |
-| Module six.moves | PY2 | bool False |
-| Module six.moves | PY3 | bool True |
-| Module six.moves | SimpleHTTPServer | Module http.server |
-| Module six.moves | StringIO | builtin-class _io.StringIO |
-| Module six.moves | UserString | class UserString |
-| Module six.moves | __name__ | str u'six.moves' |
-| Module six.moves | _thread | Module _thread |
-| Module six.moves | builtins | Module builtins |
-| Module six.moves | cPickle | Module pickle |
-| Module six.moves | cStringIO | builtin-class _io.StringIO |
-| Module six.moves | configparser | Module configparser |
-| Module six.moves | copyreg | Module copyreg |
-| Module six.moves | dbm_gnu | Module dbm.gnu |
-| Module six.moves | email_mime_base | Module email.mime.base |
-| Module six.moves | email_mime_multipart | Module email.mime.multipart |
-| Module six.moves | email_mime_text | Module email.mime.text |
-| Module six.moves | filter | builtin-class filter |
-| Module six.moves | filterfalse | builtin-class itertools.filterfalse |
-| Module six.moves | html_entities | Module html.entities |
-| Module six.moves | html_parser | Module html.parser |
-| Module six.moves | http_client | Module http.client |
-| Module six.moves | http_cookiejar | Module http.cookiejar |
-| Module six.moves | http_cookies | Module http.cookies |
-| Module six.moves | input | Builtin-function input |
-| Module six.moves | map | builtin-class map |
-| Module six.moves | queue | Module queue |
-| Module six.moves | range | builtin-class range |
-| Module six.moves | reload_module | Function reload |
-| Module six.moves | reprlib | Module reprlib |
-| Module six.moves | socketserver | Module socketserver |
-| Module six.moves | tkinter | Module tkinter |
-| Module six.moves | tkinter_colorchooser | Module tkinter.colorchooser |
-| Module six.moves | tkinter_commondialog | Module tkinter.commondialog |
-| Module six.moves | tkinter_constants | Module tkinter.constants |
-| Module six.moves | tkinter_dialog | Module tkinter.dialog |
-| Module six.moves | tkinter_dnd | Module tkinter.dnd |
-| Module six.moves | tkinter_filedialog | Module tkinter.filedialog |
-| Module six.moves | tkinter_font | Module tkinter.font |
-| Module six.moves | tkinter_messagebox | Module tkinter.messagebox |
-| Module six.moves | tkinter_scrolledtext | Module tkinter.scrolledtext |
-| Module six.moves | tkinter_simpledialog | Module tkinter.simpledialog |
-| Module six.moves | tkinter_tix | Module tkinter.tix |
-| Module six.moves | tkinter_tkfiledialog | Module tkinter.filedialog |
-| Module six.moves | tkinter_tksimpledialog | Module tkinter.simpledialog |
-| Module six.moves | tkinter_ttk | Module tkinter.ttk |
-| Module six.moves | urllib | Module six.moves.urllib |
-| Module six.moves | urllib_error | Module six.moves.urllib_error |
-| Module six.moves | urllib_parse | Module six.moves.urllib_parse |
-| Module six.moves | urllib_request | Module six.moves.urllib_request |
-| Module six.moves | urllib_response | Module six.moves.urllib_response |
-| Module six.moves | urllib_robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves | xmlrpc_client | Module xmlrpc.client |
-| Module six.moves | xrange | builtin-class range |
-| Module six.moves | zip | builtin-class zip |
-| Module six.moves | zip_longest | builtin-class itertools.zip_longest |
-| Module six.moves.__init__ | BaseHTTPServer | Module http.server |
-| Module six.moves.__init__ | CGIHTTPServer | Module http.server |
-| Module six.moves.__init__ | PY2 | bool False |
-| Module six.moves.__init__ | PY3 | bool True |
-| Module six.moves.__init__ | SimpleHTTPServer | Module http.server |
-| Module six.moves.__init__ | StringIO | builtin-class _io.StringIO |
-| Module six.moves.__init__ | UserString | class UserString |
-| Module six.moves.__init__ | __name__ | str u'six.moves' |
-| Module six.moves.__init__ | _thread | Module _thread |
-| Module six.moves.__init__ | builtins | Module builtins |
-| Module six.moves.__init__ | cPickle | Module pickle |
-| Module six.moves.__init__ | cStringIO | builtin-class _io.StringIO |
-| Module six.moves.__init__ | configparser | Module configparser |
-| Module six.moves.__init__ | copyreg | Module copyreg |
-| Module six.moves.__init__ | dbm_gnu | Module dbm.gnu |
-| Module six.moves.__init__ | email_mime_base | Module email.mime.base |
-| Module six.moves.__init__ | email_mime_multipart | Module email.mime.multipart |
-| Module six.moves.__init__ | email_mime_text | Module email.mime.text |
-| Module six.moves.__init__ | filter | builtin-class filter |
-| Module six.moves.__init__ | filterfalse | builtin-class itertools.filterfalse |
-| Module six.moves.__init__ | html_entities | Module html.entities |
-| Module six.moves.__init__ | html_parser | Module html.parser |
-| Module six.moves.__init__ | http_client | Module http.client |
-| Module six.moves.__init__ | http_cookiejar | Module http.cookiejar |
-| Module six.moves.__init__ | http_cookies | Module http.cookies |
-| Module six.moves.__init__ | input | Builtin-function input |
-| Module six.moves.__init__ | map | builtin-class map |
-| Module six.moves.__init__ | queue | Module queue |
-| Module six.moves.__init__ | range | builtin-class range |
-| Module six.moves.__init__ | reload_module | Function reload |
-| Module six.moves.__init__ | reprlib | Module reprlib |
-| Module six.moves.__init__ | socketserver | Module socketserver |
-| Module six.moves.__init__ | tkinter | Module tkinter |
-| Module six.moves.__init__ | tkinter_colorchooser | Module tkinter.colorchooser |
-| Module six.moves.__init__ | tkinter_commondialog | Module tkinter.commondialog |
-| Module six.moves.__init__ | tkinter_constants | Module tkinter.constants |
-| Module six.moves.__init__ | tkinter_dialog | Module tkinter.dialog |
-| Module six.moves.__init__ | tkinter_dnd | Module tkinter.dnd |
-| Module six.moves.__init__ | tkinter_filedialog | Module tkinter.filedialog |
-| Module six.moves.__init__ | tkinter_font | Module tkinter.font |
-| Module six.moves.__init__ | tkinter_messagebox | Module tkinter.messagebox |
-| Module six.moves.__init__ | tkinter_scrolledtext | Module tkinter.scrolledtext |
-| Module six.moves.__init__ | tkinter_simpledialog | Module tkinter.simpledialog |
-| Module six.moves.__init__ | tkinter_tix | Module tkinter.tix |
-| Module six.moves.__init__ | tkinter_tkfiledialog | Module tkinter.filedialog |
-| Module six.moves.__init__ | tkinter_tksimpledialog | Module tkinter.simpledialog |
-| Module six.moves.__init__ | tkinter_ttk | Module tkinter.ttk |
-| Module six.moves.__init__ | urllib | Module six.moves.urllib |
-| Module six.moves.__init__ | urllib_error | Module six.moves.urllib_error |
-| Module six.moves.__init__ | urllib_parse | Module six.moves.urllib_parse |
-| Module six.moves.__init__ | urllib_request | Module six.moves.urllib_request |
-| Module six.moves.__init__ | urllib_response | Module six.moves.urllib_response |
-| Module six.moves.__init__ | urllib_robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves.__init__ | xmlrpc_client | Module xmlrpc.client |
-| Module six.moves.__init__ | xrange | builtin-class range |
-| Module six.moves.__init__ | zip | builtin-class zip |
-| Module six.moves.__init__ | zip_longest | builtin-class itertools.zip_longest |
-| Module six.moves.urllib | __name__ | str u'six.moves.urllib' |
-| Module six.moves.urllib | error | Module six.moves.urllib_error |
-| Module six.moves.urllib | parse | Module six.moves.urllib_parse |
-| Module six.moves.urllib | request | Module six.moves.urllib_request |
-| Module six.moves.urllib | response | Module six.moves.urllib_response |
-| Module six.moves.urllib | robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves.urllib.__init__ | __name__ | str u'six.moves.urllib' |
-| Module six.moves.urllib.__init__ | error | Module six.moves.urllib_error |
-| Module six.moves.urllib.__init__ | parse | Module six.moves.urllib_parse |
-| Module six.moves.urllib.__init__ | request | Module six.moves.urllib_request |
-| Module six.moves.urllib.__init__ | response | Module six.moves.urllib_response |
-| Module six.moves.urllib.__init__ | robotparser | Module six.moves.urllib_robotparser |
-| Module six.moves.urllib_error | PY2 | bool False |
-| Module six.moves.urllib_error | PY3 | bool True |
-| Module six.moves.urllib_error | __name__ | str u'six.moves.urllib_error' |
-| Module six.moves.urllib_parse | PY2 | bool False |
-| Module six.moves.urllib_parse | PY3 | bool True |
-| Module six.moves.urllib_parse | __name__ | str u'six.moves.urllib_parse' |
-| Module six.moves.urllib_request | PY2 | bool False |
-| Module six.moves.urllib_request | PY3 | bool True |
-| Module six.moves.urllib_request | __name__ | str u'six.moves.urllib_request' |
-| Module six.moves.urllib_response | PY2 | bool False |
-| Module six.moves.urllib_response | PY3 | bool True |
-| Module six.moves.urllib_response | __name__ | str u'six.moves.urllib_response' |
-| Module six.moves.urllib_robotparser | PY2 | bool False |
-| Module six.moves.urllib_robotparser | PY3 | bool True |
-| Module six.moves.urllib_robotparser | RobotFileParser | class RobotFileParser |
-| Module six.moves.urllib_robotparser | __name__ | str u'six.moves.urllib_robotparser' |
diff --git a/python/ql/test/3/library-tests/six/test.py b/python/ql/test/3/library-tests/six/test.py
index 6cffe08b96c..cac31dceb8a 100644
--- a/python/ql/test/3/library-tests/six/test.py
+++ b/python/ql/test/3/library-tests/six/test.py
@@ -1,5 +1,9 @@
import six
-#Check that some expected attributes are visible
+# Check that some expected attributes are visible -- this is the reason we added stubs in
+# the first place! If this works, we're happy!
six.moves
-six.moves.range
\ No newline at end of file
+six.moves.range
+six.moves.zip
+six.moves.http_client.HTTPConnection
+six.moves.urllib.parse.urlsplit
diff --git a/python/ql/test/3/library-tests/six/test.ql b/python/ql/test/3/library-tests/six/test.ql
deleted file mode 100644
index 5d694b9fec9..00000000000
--- a/python/ql/test/3/library-tests/six/test.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-import python
-
-predicate six(ModuleObject m) {
- m.getName() = "six"
- or
- six(m.getPackage())
-}
-
-from ModuleObject mod, string name, Object obj
-where mod.attributeRefersTo(name, obj, _) and six(mod)
-select mod.toString(), name, obj.toString()
diff --git a/python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected b/python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected
new file mode 100644
index 00000000000..c8f60f6a596
--- /dev/null
+++ b/python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected
@@ -0,0 +1,4 @@
+| test.py:9:12:9:26 | bottle handler function result | externally controlled string |
+| test.py:13:12:13:24 | bottle handler function result | externally controlled string |
+| test.py:19:12:19:33 | bottle handler function result | externally controlled string |
+| test.py:36:21:36:51 | Taint sink | externally controlled string |
diff --git a/python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql b/python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/bottle/HttpSources.expected b/python/ql/test/library-tests/web/bottle/HttpSources.expected
new file mode 100644
index 00000000000..41e68da26d9
--- /dev/null
+++ b/python/ql/test/library-tests/web/bottle/HttpSources.expected
@@ -0,0 +1,8 @@
+| ../../../query-tests/Security/lib/bottle.py:64:11:64:24 | LocalRequest() | bottle.request |
+| test.py:3:35:3:41 | ImportMember | bottle.request |
+| test.py:8:11:8:14 | name | externally controlled string |
+| test.py:12:9:12:12 | name | externally controlled string |
+| test.py:18:12:18:18 | request | bottle.request |
+| test.py:27:12:27:16 | where | externally controlled string |
+| test.py:32:14:32:20 | request | bottle.request |
+| test.py:36:34:36:40 | request | bottle.request |
diff --git a/python/ql/test/library-tests/web/bottle/HttpSources.ql b/python/ql/test/library-tests/web/bottle/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/bottle/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/bottle/Routing.ql b/python/ql/test/library-tests/web/bottle/Routing.ql
index 3a10c78ddcb..988b8398f04 100644
--- a/python/ql/test/library-tests/web/bottle/Routing.ql
+++ b/python/ql/test/library-tests/web/bottle/Routing.ql
@@ -1,7 +1,5 @@
import python
-
import semmle.python.web.bottle.General
from BottleRoute route
-
select route.getUrl(), route.getFunction()
diff --git a/python/ql/test/library-tests/web/bottle/Sinks.expected b/python/ql/test/library-tests/web/bottle/Sinks.expected
deleted file mode 100644
index 64edd29140f..00000000000
--- a/python/ql/test/library-tests/web/bottle/Sinks.expected
+++ /dev/null
@@ -1,4 +0,0 @@
-| test.py:9 | BinaryExpr | externally controlled string |
-| test.py:13 | BinaryExpr | externally controlled string |
-| test.py:19 | BinaryExpr | externally controlled string |
-| test.py:36 | BinaryExpr | externally controlled string |
diff --git a/python/ql/test/library-tests/web/bottle/Sinks.ql b/python/ql/test/library-tests/web/bottle/Sinks.ql
deleted file mode 100644
index 34aa1cfc429..00000000000
--- a/python/ql/test/library-tests/web/bottle/Sinks.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/bottle/Sources.expected b/python/ql/test/library-tests/web/bottle/Sources.expected
deleted file mode 100644
index 46c419efb95..00000000000
--- a/python/ql/test/library-tests/web/bottle/Sources.expected
+++ /dev/null
@@ -1,8 +0,0 @@
-| ../../../query-tests/Security/lib/bottle.py:64 | LocalRequest() | bottle.request |
-| test.py:3 | ImportMember | bottle.request |
-| test.py:8 | name | externally controlled string |
-| test.py:12 | name | externally controlled string |
-| test.py:18 | request | bottle.request |
-| test.py:27 | where | externally controlled string |
-| test.py:32 | request | bottle.request |
-| test.py:36 | request | bottle.request |
diff --git a/python/ql/test/library-tests/web/bottle/Sources.ql b/python/ql/test/library-tests/web/bottle/Sources.ql
deleted file mode 100644
index c1b9cc82e19..00000000000
--- a/python/ql/test/library-tests/web/bottle/Sources.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind) and not kind.matches("tornado%")
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/bottle/Taint.ql b/python/ql/test/library-tests/web/bottle/Taint.ql
index 2c74191e645..09972af5f98 100644
--- a/python/ql/test/library-tests/web/bottle/Taint.ql
+++ b/python/ql/test/library-tests/web/bottle/Taint.ql
@@ -1,13 +1,7 @@
-
import python
-
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
-
from TaintedNode node
-
select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind()
-
diff --git a/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected b/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected
new file mode 100644
index 00000000000..0d7a43a2b07
--- /dev/null
+++ b/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected
@@ -0,0 +1,3 @@
+| red.py:8:16:8:20 | cherrypy handler function result | externally controlled string |
+| test.py:11:16:11:29 | cherrypy handler function result | externally controlled string |
+| test.py:17:16:17:27 | cherrypy handler function result | externally controlled string |
diff --git a/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql b/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/cherrypy/HttpSources.expected b/python/ql/test/library-tests/web/cherrypy/HttpSources.expected
new file mode 100644
index 00000000000..205cc9caaa8
--- /dev/null
+++ b/python/ql/test/library-tests/web/cherrypy/HttpSources.expected
@@ -0,0 +1,3 @@
+| ../../../query-tests/Security/lib/cherrypy/__init__.py:10:11:10:38 | _ThreadLocalProxy() | cherrypy.request |
+| test.py:10:17:10:19 | arg | externally controlled string |
+| test.py:16:17:16:19 | arg | externally controlled string |
diff --git a/python/ql/test/library-tests/web/cherrypy/HttpSources.ql b/python/ql/test/library-tests/web/cherrypy/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/cherrypy/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/cherrypy/Sinks.expected b/python/ql/test/library-tests/web/cherrypy/Sinks.expected
deleted file mode 100644
index e47936b055c..00000000000
--- a/python/ql/test/library-tests/web/cherrypy/Sinks.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| red.py:8 | Str | externally controlled string |
-| test.py:11 | BinaryExpr | externally controlled string |
-| test.py:17 | BinaryExpr | externally controlled string |
diff --git a/python/ql/test/library-tests/web/cherrypy/Sinks.ql b/python/ql/test/library-tests/web/cherrypy/Sinks.ql
deleted file mode 100644
index 34aa1cfc429..00000000000
--- a/python/ql/test/library-tests/web/cherrypy/Sinks.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/cherrypy/Sources.expected b/python/ql/test/library-tests/web/cherrypy/Sources.expected
deleted file mode 100644
index b2a4d2e7c3e..00000000000
--- a/python/ql/test/library-tests/web/cherrypy/Sources.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | _ThreadLocalProxy() | cherrypy.request |
-| test.py:10 | arg | externally controlled string |
-| test.py:16 | arg | externally controlled string |
diff --git a/python/ql/test/library-tests/web/cherrypy/Sources.ql b/python/ql/test/library-tests/web/cherrypy/Sources.ql
deleted file mode 100644
index c1b9cc82e19..00000000000
--- a/python/ql/test/library-tests/web/cherrypy/Sources.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind) and not kind.matches("tornado%")
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected
new file mode 100644
index 00000000000..28bda6b1d30
--- /dev/null
+++ b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected
@@ -0,0 +1,7 @@
+| views.py:7:25:7:63 | django.Response(...) | externally controlled string |
+| views.py:11:25:11:52 | django.Response(...) | externally controlled string |
+| views.py:15:25:15:53 | django.Response(...) | externally controlled string |
+| views.py:23:29:23:60 | django.Response(...) | externally controlled string |
+| views.py:29:29:29:65 | django.Response(...) | externally controlled string |
+| views.py:34:25:34:63 | django.Response(...) | externally controlled string |
+| views.py:38:25:38:70 | django.Response(...) | externally controlled string |
diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.ql b/python/ql/test/library-tests/web/django/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/django/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/django/HttpSources.expected b/python/ql/test/library-tests/web/django/HttpSources.expected
new file mode 100644
index 00000000000..1c25023d0b4
--- /dev/null
+++ b/python/ql/test/library-tests/web/django/HttpSources.expected
@@ -0,0 +1,19 @@
+| test.py:5:19:5:25 | request | django.request.HttpRequest |
+| test.py:5:28:5:31 | path | externally controlled string |
+| test.py:11:19:11:25 | request | django.request.HttpRequest |
+| test.py:11:28:11:31 | path | externally controlled string |
+| views.py:6:19:6:25 | request | django.request.HttpRequest |
+| views.py:6:28:6:30 | foo | externally controlled string |
+| views.py:6:33:6:35 | bar | externally controlled string |
+| views.py:10:20:10:26 | request | django.request.HttpRequest |
+| views.py:14:21:14:27 | request | django.request.HttpRequest |
+| views.py:22:20:22:26 | request | django.request.HttpRequest |
+| views.py:28:19:28:25 | request | django.request.HttpRequest |
+| views.py:32:19:32:25 | request | django.request.HttpRequest |
+| views.py:32:28:32:38 | page_number | externally controlled string |
+| views.py:37:24:37:30 | request | django.request.HttpRequest |
+| views.py:37:33:37:36 | arg0 | externally controlled string |
+| views.py:37:39:37:42 | arg1 | externally controlled string |
+| views.py:57:15:57:21 | request | django.request.HttpRequest |
+| views.py:57:24:57:31 | username | externally controlled string |
+| views.py:66:30:66:36 | request | django.request.HttpRequest |
diff --git a/python/ql/test/library-tests/web/django/HttpSources.ql b/python/ql/test/library-tests/web/django/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/django/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/django/Sinks.expected b/python/ql/test/library-tests/web/django/Sinks.expected
deleted file mode 100644
index e3d233c9990..00000000000
--- a/python/ql/test/library-tests/web/django/Sinks.expected
+++ /dev/null
@@ -1,16 +0,0 @@
-| sql.py:13 | Str | externally controlled string |
-| sql.py:14 | Str | externally controlled string |
-| sql.py:17 | BinaryExpr | externally controlled string |
-| sql.py:20 | BinaryExpr | externally controlled string |
-| sql.py:21 | BinaryExpr | externally controlled string |
-| sql.py:22 | BinaryExpr | externally controlled string |
-| sql.py:36 | Str | externally controlled string |
-| sql.py:42 | BinaryExpr | externally controlled string |
-| sql.py:47 | BinaryExpr | externally controlled string |
-| views.py:7 | Attribute() | externally controlled string |
-| views.py:11 | Attribute() | externally controlled string |
-| views.py:15 | Attribute() | externally controlled string |
-| views.py:23 | Attribute() | externally controlled string |
-| views.py:29 | Attribute() | externally controlled string |
-| views.py:34 | Attribute() | externally controlled string |
-| views.py:38 | Attribute() | externally controlled string |
diff --git a/python/ql/test/library-tests/web/django/Sinks.ql b/python/ql/test/library-tests/web/django/Sinks.ql
deleted file mode 100644
index 5bdf37e4f44..00000000000
--- a/python/ql/test/library-tests/web/django/Sinks.ql
+++ /dev/null
@@ -1,13 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.web.django.Db
-import semmle.python.web.django.Model
-
-import semmle.python.security.strings.Untrusted
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/django/Sources.expected b/python/ql/test/library-tests/web/django/Sources.expected
deleted file mode 100644
index 35e0d3d8ced..00000000000
--- a/python/ql/test/library-tests/web/django/Sources.expected
+++ /dev/null
@@ -1,19 +0,0 @@
-| test.py:5 | path | externally controlled string |
-| test.py:5 | request | django.request.HttpRequest |
-| test.py:11 | path | externally controlled string |
-| test.py:11 | request | django.request.HttpRequest |
-| views.py:6 | bar | externally controlled string |
-| views.py:6 | foo | externally controlled string |
-| views.py:6 | request | django.request.HttpRequest |
-| views.py:10 | request | django.request.HttpRequest |
-| views.py:14 | request | django.request.HttpRequest |
-| views.py:22 | request | django.request.HttpRequest |
-| views.py:28 | request | django.request.HttpRequest |
-| views.py:32 | page_number | externally controlled string |
-| views.py:32 | request | django.request.HttpRequest |
-| views.py:37 | arg0 | externally controlled string |
-| views.py:37 | arg1 | externally controlled string |
-| views.py:37 | request | django.request.HttpRequest |
-| views.py:57 | request | django.request.HttpRequest |
-| views.py:57 | username | externally controlled string |
-| views.py:66 | request | django.request.HttpRequest |
diff --git a/python/ql/test/library-tests/web/django/Sources.ql b/python/ql/test/library-tests/web/django/Sources.ql
deleted file mode 100644
index aece91f44e2..00000000000
--- a/python/ql/test/library-tests/web/django/Sources.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind)
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/django/SqlInjectionSinks.expected b/python/ql/test/library-tests/web/django/SqlInjectionSinks.expected
new file mode 100644
index 00000000000..d9850f2f7c6
--- /dev/null
+++ b/python/ql/test/library-tests/web/django/SqlInjectionSinks.expected
@@ -0,0 +1,9 @@
+| sql.py:13:24:13:64 | db.connection.execute | externally controlled string |
+| sql.py:14:26:14:66 | django.models.QuerySet.raw(sink,...) | externally controlled string |
+| sql.py:17:24:17:77 | db.connection.execute | externally controlled string |
+| sql.py:20:38:20:95 | django.db.models.expressions.RawSQL(sink,...) | externally controlled string |
+| sql.py:21:26:21:83 | django.models.QuerySet.raw(sink,...) | externally controlled string |
+| sql.py:22:28:22:85 | django.models.QuerySet.extra(sink,...) | externally controlled string |
+| sql.py:36:26:36:68 | django.models.QuerySet.raw(sink,...) | externally controlled string |
+| sql.py:42:11:42:52 | django.models.QuerySet.raw(sink,...) | externally controlled string |
+| sql.py:47:13:47:54 | django.models.QuerySet.extra(sink,...) | externally controlled string |
diff --git a/python/ql/test/library-tests/web/django/SqlInjectionSinks.ql b/python/ql/test/library-tests/web/django/SqlInjectionSinks.ql
new file mode 100644
index 00000000000..bd9f4c22fc8
--- /dev/null
+++ b/python/ql/test/library-tests/web/django/SqlInjectionSinks.ql
@@ -0,0 +1,9 @@
+import python
+import semmle.python.security.injection.Sql
+import semmle.python.web.django.Db
+import semmle.python.web.django.Model
+import semmle.python.security.strings.Untrusted
+
+from SqlInjectionSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected b/python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected
new file mode 100644
index 00000000000..76fe8773866
--- /dev/null
+++ b/python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected
@@ -0,0 +1 @@
+| FIXME: temporarily disabled since it's not working |
diff --git a/python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql b/python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql
new file mode 100644
index 00000000000..eec9b1ef3cf
--- /dev/null
+++ b/python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql
@@ -0,0 +1,8 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+// from HttpResponseTaintSink sink, TaintKind kind
+// where sink.sinks(kind)
+// select sink, kind
+select "FIXME: temporarily disabled since it's not working"
diff --git a/python/ql/test/library-tests/web/falcon/HttpSources.expected b/python/ql/test/library-tests/web/falcon/HttpSources.expected
new file mode 100644
index 00000000000..247015db674
--- /dev/null
+++ b/python/ql/test/library-tests/web/falcon/HttpSources.expected
@@ -0,0 +1,3 @@
+| test.py:9:22:9:24 | req | falcon.request |
+| test.py:19:23:19:25 | req | falcon.request |
+| test.py:22:25:22:27 | req | falcon.request |
diff --git a/python/ql/test/library-tests/web/falcon/HttpSources.ql b/python/ql/test/library-tests/web/falcon/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/falcon/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/falcon/Routing.ql b/python/ql/test/library-tests/web/falcon/Routing.ql
index 0596664ba76..fde6c933b65 100644
--- a/python/ql/test/library-tests/web/falcon/Routing.ql
+++ b/python/ql/test/library-tests/web/falcon/Routing.ql
@@ -1,8 +1,5 @@
import python
-
import semmle.python.web.falcon.General
from FalconRoute route, string method
-
select route.getUrl(), method, route.getHandlerFunction(method)
-
diff --git a/python/ql/test/library-tests/web/falcon/Sinks.ql b/python/ql/test/library-tests/web/falcon/Sinks.ql
index 34aa1cfc429..efaafe17f02 100644
--- a/python/ql/test/library-tests/web/falcon/Sinks.ql
+++ b/python/ql/test/library-tests/web/falcon/Sinks.ql
@@ -1,6 +1,4 @@
-
import python
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
diff --git a/python/ql/test/library-tests/web/falcon/Sources.expected b/python/ql/test/library-tests/web/falcon/Sources.expected
deleted file mode 100644
index f2ed444a751..00000000000
--- a/python/ql/test/library-tests/web/falcon/Sources.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| test.py:9 | req | falcon.request |
-| test.py:19 | req | falcon.request |
-| test.py:22 | req | falcon.request |
\ No newline at end of file
diff --git a/python/ql/test/library-tests/web/falcon/Sources.ql b/python/ql/test/library-tests/web/falcon/Sources.ql
deleted file mode 100644
index c1b9cc82e19..00000000000
--- a/python/ql/test/library-tests/web/falcon/Sources.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind) and not kind.matches("tornado%")
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/falcon/Taint.ql b/python/ql/test/library-tests/web/falcon/Taint.ql
index 59dbe108f62..d68b12079b8 100644
--- a/python/ql/test/library-tests/web/falcon/Taint.ql
+++ b/python/ql/test/library-tests/web/falcon/Taint.ql
@@ -1,12 +1,8 @@
-
import python
-
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
-
from TaintedNode node
where node.getLocation().getFile().getShortName() = "test.py"
select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind()
diff --git a/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected b/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected
new file mode 100644
index 00000000000..5581b7fd3ad
--- /dev/null
+++ b/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected
@@ -0,0 +1,8 @@
+| test.py:8:12:8:25 | flask.routed.response | externally controlled string |
+| test.py:29:12:29:38 | flask.routed.response | externally controlled string |
+| test.py:35:16:35:37 | flask.routed.response | externally controlled string |
+| test.py:36:12:36:15 | flask.routed.response | externally controlled string |
+| test.py:41:12:41:54 | flask.routed.response | externally controlled string |
+| test.py:41:26:41:53 | flask.response.argument | externally controlled string |
+| test.py:46:12:46:62 | flask.routed.response | externally controlled string |
+| test.py:46:26:46:61 | flask.response.argument | externally controlled string |
diff --git a/python/ql/test/library-tests/web/flask/HttpResponseSinks.ql b/python/ql/test/library-tests/web/flask/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/flask/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/flask/HttpSources.expected b/python/ql/test/library-tests/web/flask/HttpSources.expected
new file mode 100644
index 00000000000..7899304bb4f
--- /dev/null
+++ b/python/ql/test/library-tests/web/flask/HttpSources.expected
@@ -0,0 +1,5 @@
+| test.py:29:12:29:23 | Attribute | {externally controlled string} |
+| test.py:33:9:33:20 | Attribute | {externally controlled string} |
+| test.py:35:16:35:27 | Attribute | {externally controlled string} |
+| test.py:40:18:40:29 | Attribute | {externally controlled string} |
+| test.py:45:18:45:29 | Attribute | {externally controlled string} |
diff --git a/python/ql/test/library-tests/web/flask/HttpSources.ql b/python/ql/test/library-tests/web/flask/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/flask/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/flask/Routing.ql b/python/ql/test/library-tests/web/flask/Routing.ql
index ebd0ec93abb..92ae6740f0d 100644
--- a/python/ql/test/library-tests/web/flask/Routing.ql
+++ b/python/ql/test/library-tests/web/flask/Routing.ql
@@ -1,9 +1,6 @@
import python
-
import semmle.python.web.flask.General
from ControlFlowNode regex, Function func
-
where flask_routing(regex, func)
-
select regex.getNode().(StrConst).getText(), func.toString()
diff --git a/python/ql/test/library-tests/web/flask/Sinks.expected b/python/ql/test/library-tests/web/flask/Sinks.expected
deleted file mode 100644
index 741ab7d4d38..00000000000
--- a/python/ql/test/library-tests/web/flask/Sinks.expected
+++ /dev/null
@@ -1,8 +0,0 @@
-| test.py:8 | Str | externally controlled string |
-| test.py:29 | Attribute() | externally controlled string |
-| test.py:35 | Subscript | externally controlled string |
-| test.py:36 | None | externally controlled string |
-| test.py:41 | BinaryExpr | externally controlled string |
-| test.py:41 | make_response() | externally controlled string |
-| test.py:46 | BinaryExpr | externally controlled string |
-| test.py:46 | make_response() | externally controlled string |
diff --git a/python/ql/test/library-tests/web/flask/Sinks.ql b/python/ql/test/library-tests/web/flask/Sinks.ql
deleted file mode 100644
index 34aa1cfc429..00000000000
--- a/python/ql/test/library-tests/web/flask/Sinks.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/flask/Sources.expected b/python/ql/test/library-tests/web/flask/Sources.expected
deleted file mode 100644
index 09b626643a1..00000000000
--- a/python/ql/test/library-tests/web/flask/Sources.expected
+++ /dev/null
@@ -1,6 +0,0 @@
-| test.py:22 | Attribute() | flask/MyView.as.view |
-| test.py:29 | Attribute | {externally controlled string} |
-| test.py:33 | Attribute | {externally controlled string} |
-| test.py:35 | Attribute | {externally controlled string} |
-| test.py:40 | Attribute | {externally controlled string} |
-| test.py:45 | Attribute | {externally controlled string} |
diff --git a/python/ql/test/library-tests/web/flask/Sources.ql b/python/ql/test/library-tests/web/flask/Sources.ql
deleted file mode 100644
index b1b7fe3e08b..00000000000
--- a/python/ql/test/library-tests/web/flask/Sources.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind)
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/flask/Taint.ql b/python/ql/test/library-tests/web/flask/Taint.ql
index 59dbe108f62..d68b12079b8 100644
--- a/python/ql/test/library-tests/web/flask/Taint.ql
+++ b/python/ql/test/library-tests/web/flask/Taint.ql
@@ -1,12 +1,8 @@
-
import python
-
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
-
from TaintedNode node
where node.getLocation().getFile().getShortName() = "test.py"
select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind()
diff --git a/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected b/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected
new file mode 100644
index 00000000000..c5791c9c976
--- /dev/null
+++ b/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected
@@ -0,0 +1,3 @@
+| test.py:8:12:8:31 | pyramid.routed.response | externally controlled string |
+| test.py:17:12:17:41 | pyramid.routed.response | externally controlled string |
+| test.py:25:12:25:43 | pyramid.routed.response | externally controlled string |
diff --git a/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql b/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/pyramid/HttpSources.expected b/python/ql/test/library-tests/web/pyramid/HttpSources.expected
new file mode 100644
index 00000000000..7a07771b188
--- /dev/null
+++ b/python/ql/test/library-tests/web/pyramid/HttpSources.expected
@@ -0,0 +1,3 @@
+| test.py:7:10:7:16 | request | pyramid.request |
+| test.py:15:11:15:17 | request | pyramid.request |
+| test.py:24:11:24:17 | request | pyramid.request |
diff --git a/python/ql/test/library-tests/web/pyramid/HttpSources.ql b/python/ql/test/library-tests/web/pyramid/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/pyramid/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/pyramid/Routing.ql b/python/ql/test/library-tests/web/pyramid/Routing.ql
index ef21e5510fe..4a442c1115e 100644
--- a/python/ql/test/library-tests/web/pyramid/Routing.ql
+++ b/python/ql/test/library-tests/web/pyramid/Routing.ql
@@ -1,9 +1,6 @@
import python
-
import semmle.python.web.pyramid.View
from Function func
-
where is_pyramid_view_function(func)
-
select func.getLocation().toString(), func.toString()
diff --git a/python/ql/test/library-tests/web/pyramid/Sinks.expected b/python/ql/test/library-tests/web/pyramid/Sinks.expected
deleted file mode 100644
index 03e32dac04a..00000000000
--- a/python/ql/test/library-tests/web/pyramid/Sinks.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| test.py:8 | Response() | externally controlled string |
-| test.py:17 | Response() | externally controlled string |
-| test.py:25 | Dict | externally controlled string |
diff --git a/python/ql/test/library-tests/web/pyramid/Sinks.ql b/python/ql/test/library-tests/web/pyramid/Sinks.ql
deleted file mode 100644
index 63722622990..00000000000
--- a/python/ql/test/library-tests/web/pyramid/Sinks.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind) and sink.getLocation().getFile().getShortName() = "test.py"
-select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/pyramid/Sources.expected b/python/ql/test/library-tests/web/pyramid/Sources.expected
deleted file mode 100644
index f7fe4bb2c5c..00000000000
--- a/python/ql/test/library-tests/web/pyramid/Sources.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| test.py:7 | request | pyramid.request |
-| test.py:15 | request | pyramid.request |
-| test.py:24 | request | pyramid.request |
diff --git a/python/ql/test/library-tests/web/pyramid/Sources.ql b/python/ql/test/library-tests/web/pyramid/Sources.ql
deleted file mode 100644
index b1b7fe3e08b..00000000000
--- a/python/ql/test/library-tests/web/pyramid/Sources.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind)
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/pyramid/Taint.ql b/python/ql/test/library-tests/web/pyramid/Taint.ql
index 2c67c626aaa..d68b12079b8 100644
--- a/python/ql/test/library-tests/web/pyramid/Taint.ql
+++ b/python/ql/test/library-tests/web/pyramid/Taint.ql
@@ -1,11 +1,8 @@
-
import python
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
from TaintedNode node
where node.getLocation().getFile().getShortName() = "test.py"
-
select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind()
diff --git a/python/ql/test/library-tests/web/tornado/Classes.ql b/python/ql/test/library-tests/web/tornado/Classes.ql
index 08346af0dcf..fda9b6eb00a 100644
--- a/python/ql/test/library-tests/web/tornado/Classes.ql
+++ b/python/ql/test/library-tests/web/tornado/Classes.ql
@@ -1,9 +1,7 @@
-
import python
-
import semmle.python.TestUtils
-
import semmle.python.web.tornado.Tornado
+
from ClassValue cls
where cls = aTornadoRequestHandlerClass()
select remove_library_prefix(cls.getScope().getLocation()), cls.toString()
diff --git a/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected b/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected
new file mode 100644
index 00000000000..c262f5b6bbb
--- /dev/null
+++ b/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected
@@ -0,0 +1 @@
+| test.py:20:23:20:25 | tornado.HttpRequestHandler.redirect | externally controlled string |
diff --git a/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql b/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql
new file mode 100644
index 00000000000..157ef2d4430
--- /dev/null
+++ b/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRedirect
+import semmle.python.security.strings.Untrusted
+
+from HttpRedirectTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected b/python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected
new file mode 100644
index 00000000000..0309c54ceb5
--- /dev/null
+++ b/python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected
@@ -0,0 +1,3 @@
+| test.py:6:20:6:43 | tornado.HttpRequestHandler.write | externally controlled string |
+| test.py:12:20:12:23 | tornado.HttpRequestHandler.write | externally controlled string |
+| test.py:26:20:26:48 | tornado.HttpRequestHandler.write | externally controlled string |
diff --git a/python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql b/python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/tornado/HttpSources.expected b/python/ql/test/library-tests/web/tornado/HttpSources.expected
new file mode 100644
index 00000000000..bcab5502996
--- /dev/null
+++ b/python/ql/test/library-tests/web/tornado/HttpSources.expected
@@ -0,0 +1,4 @@
+| test.py:6:20:6:43 | Attribute() | externally controlled string |
+| test.py:10:16:10:40 | Attribute() | [externally controlled string] |
+| test.py:17:15:17:26 | Attribute | tornado.request.HttpRequest |
+| test.py:26:20:26:48 | Attribute() | externally controlled string |
diff --git a/python/ql/test/library-tests/web/tornado/HttpSources.ql b/python/ql/test/library-tests/web/tornado/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/tornado/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/tornado/Sinks.expected b/python/ql/test/library-tests/web/tornado/Sinks.expected
deleted file mode 100644
index d493bb82ee3..00000000000
--- a/python/ql/test/library-tests/web/tornado/Sinks.expected
+++ /dev/null
@@ -1,4 +0,0 @@
-| test.py:6 | Attribute() | externally controlled string |
-| test.py:12 | name | externally controlled string |
-| test.py:20 | url | externally controlled string |
-| test.py:26 | Attribute() | externally controlled string |
diff --git a/python/ql/test/library-tests/web/tornado/Sinks.ql b/python/ql/test/library-tests/web/tornado/Sinks.ql
deleted file mode 100644
index 7d338fe63c6..00000000000
--- a/python/ql/test/library-tests/web/tornado/Sinks.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-import semmle.python.TestUtils
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select remove_library_prefix(sink.getLocation()), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/tornado/Sources.expected b/python/ql/test/library-tests/web/tornado/Sources.expected
deleted file mode 100644
index 78fb140df3c..00000000000
--- a/python/ql/test/library-tests/web/tornado/Sources.expected
+++ /dev/null
@@ -1,4 +0,0 @@
-| test.py:6 | Attribute() | externally controlled string |
-| test.py:10 | Attribute() | [externally controlled string] |
-| test.py:17 | Attribute | tornado.request.HttpRequest |
-| test.py:26 | Attribute() | externally controlled string |
diff --git a/python/ql/test/library-tests/web/tornado/Sources.ql b/python/ql/test/library-tests/web/tornado/Sources.ql
deleted file mode 100644
index 164f45d627b..00000000000
--- a/python/ql/test/library-tests/web/tornado/Sources.ql
+++ /dev/null
@@ -1,13 +0,0 @@
-
-import python
-
-import semmle.python.TestUtils
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind)
-select remove_library_prefix(src.getLocation()), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/tornado/Taint.ql b/python/ql/test/library-tests/web/tornado/Taint.ql
index d0b1d327341..d4fc34b643c 100644
--- a/python/ql/test/library-tests/web/tornado/Taint.ql
+++ b/python/ql/test/library-tests/web/tornado/Taint.ql
@@ -1,8 +1,5 @@
-
import python
-
import semmle.python.TestUtils
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
@@ -11,4 +8,3 @@ from TaintedNode node
// Add this restriction to keep Python2 and 3 results the same.
where not exists(node.getContext().getCaller())
select remove_library_prefix(node.getLocation()), node.getAstNode().toString(), node.getTaintKind()
-
diff --git a/python/ql/test/library-tests/web/turbogears/Controller.ql b/python/ql/test/library-tests/web/turbogears/Controller.ql
index a21462ffadb..850e56ef453 100644
--- a/python/ql/test/library-tests/web/turbogears/Controller.ql
+++ b/python/ql/test/library-tests/web/turbogears/Controller.ql
@@ -1,9 +1,5 @@
-
-
import python
-
import semmle.python.web.turbogears.TurboGears
from TurboGearsControllerMethod m
select m
-
diff --git a/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected b/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected
new file mode 100644
index 00000000000..bb2cc079e15
--- /dev/null
+++ b/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected
@@ -0,0 +1,5 @@
+| test.py:8:16:8:69 | TurboGears ControllerMethodReturnValue | externally controlled string |
+| test.py:14:16:14:50 | TurboGears ControllerMethodReturnValue | externally controlled string |
+| test.py:19:16:19:50 | TurboGears ControllerMethodReturnValue | externally controlled string |
+| test.py:23:16:23:50 | TurboGears ControllerMethodReturnValue | externally controlled string |
+| test.py:27:16:27:38 | TurboGears ControllerMethodTemplatedReturnValue | {externally controlled string} |
diff --git a/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql b/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/turbogears/HttpSources.expected b/python/ql/test/library-tests/web/turbogears/HttpSources.expected
new file mode 100644
index 00000000000..cae6b169eb6
--- /dev/null
+++ b/python/ql/test/library-tests/web/turbogears/HttpSources.expected
@@ -0,0 +1,3 @@
+| test.py:18:43:18:43 | b | externally controlled string |
+| test.py:22:29:22:29 | a | externally controlled string |
+| test.py:22:37:22:37 | b | externally controlled string |
diff --git a/python/ql/test/library-tests/web/turbogears/HttpSources.ql b/python/ql/test/library-tests/web/turbogears/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/turbogears/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/turbogears/Sinks.expected b/python/ql/test/library-tests/web/turbogears/Sinks.expected
deleted file mode 100644
index b528861c340..00000000000
--- a/python/ql/test/library-tests/web/turbogears/Sinks.expected
+++ /dev/null
@@ -1,5 +0,0 @@
-| test.py:8 | BinaryExpr | externally controlled string |
-| test.py:14 | BinaryExpr | externally controlled string |
-| test.py:19 | BinaryExpr | externally controlled string |
-| test.py:23 | BinaryExpr | externally controlled string |
-| test.py:27 | Dict | {externally controlled string} |
diff --git a/python/ql/test/library-tests/web/turbogears/Sinks.ql b/python/ql/test/library-tests/web/turbogears/Sinks.ql
deleted file mode 100644
index 34aa1cfc429..00000000000
--- a/python/ql/test/library-tests/web/turbogears/Sinks.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/turbogears/Sources.expected b/python/ql/test/library-tests/web/turbogears/Sources.expected
deleted file mode 100644
index fe82da5847e..00000000000
--- a/python/ql/test/library-tests/web/turbogears/Sources.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| test.py:18 | b | externally controlled string |
-| test.py:22 | a | externally controlled string |
-| test.py:22 | b | externally controlled string |
diff --git a/python/ql/test/library-tests/web/turbogears/Sources.ql b/python/ql/test/library-tests/web/turbogears/Sources.ql
deleted file mode 100644
index aece91f44e2..00000000000
--- a/python/ql/test/library-tests/web/turbogears/Sources.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind)
-select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/turbogears/Taint.ql b/python/ql/test/library-tests/web/turbogears/Taint.ql
index 2c74191e645..09972af5f98 100644
--- a/python/ql/test/library-tests/web/turbogears/Taint.ql
+++ b/python/ql/test/library-tests/web/turbogears/Taint.ql
@@ -1,13 +1,7 @@
-
import python
-
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
-
from TaintedNode node
-
select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind()
-
diff --git a/python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected b/python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected
new file mode 100644
index 00000000000..ab5b0f5a4a8
--- /dev/null
+++ b/python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected
@@ -0,0 +1,10 @@
+| test.py:7:16:7:23 | Twisted response | externally controlled string |
+| test.py:14:16:14:23 | Twisted response | externally controlled string |
+| test.py:21:16:21:23 | Twisted response | externally controlled string |
+| test.py:36:16:36:37 | Twisted response | externally controlled string |
+| test.py:40:23:40:30 | Twisted request setter | externally controlled string |
+| test.py:44:27:44:31 | Twisted request setter | externally controlled string |
+| test.py:44:34:44:38 | Twisted request setter | externally controlled string |
+| test.py:45:27:45:31 | Twisted request setter | externally controlled string |
+| test.py:45:34:45:40 | Twisted request setter | externally controlled string |
+| test.py:46:16:46:37 | Twisted response | externally controlled string |
diff --git a/python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql b/python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql
new file mode 100644
index 00000000000..e62ec486da6
--- /dev/null
+++ b/python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpResponse
+import semmle.python.security.strings.Untrusted
+
+from HttpResponseTaintSink sink, TaintKind kind
+where sink.sinks(kind)
+select sink, kind
diff --git a/python/ql/test/library-tests/web/twisted/HttpSources.expected b/python/ql/test/library-tests/web/twisted/HttpSources.expected
new file mode 100644
index 00000000000..9f9991e9944
--- /dev/null
+++ b/python/ql/test/library-tests/web/twisted/HttpSources.expected
@@ -0,0 +1,8 @@
+| test.py:4:22:4:28 | request | twisted.request.http.Request |
+| test.py:9:26:9:32 | request | twisted.request.http.Request |
+| test.py:16:27:16:33 | request | twisted.request.http.Request |
+| test.py:24:24:24:30 | request | twisted.request.http.Request |
+| test.py:28:22:28:30 | myrequest | twisted.request.http.Request |
+| test.py:31:27:31:37 | postrequest | twisted.request.http.Request |
+| test.py:39:22:39:28 | request | twisted.request.http.Request |
+| test.py:43:22:43:28 | request | twisted.request.http.Request |
diff --git a/python/ql/test/library-tests/web/twisted/HttpSources.ql b/python/ql/test/library-tests/web/twisted/HttpSources.ql
new file mode 100644
index 00000000000..6fa1a7d2a6b
--- /dev/null
+++ b/python/ql/test/library-tests/web/twisted/HttpSources.ql
@@ -0,0 +1,7 @@
+import python
+import semmle.python.web.HttpRequest
+import semmle.python.security.strings.Untrusted
+
+from HttpRequestTaintSource source, TaintKind kind
+where source.isSourceOf(kind)
+select source.(ControlFlowNode).getNode(), kind
diff --git a/python/ql/test/library-tests/web/twisted/Sinks.expected b/python/ql/test/library-tests/web/twisted/Sinks.expected
deleted file mode 100644
index f416a03e4b7..00000000000
--- a/python/ql/test/library-tests/web/twisted/Sinks.expected
+++ /dev/null
@@ -1,8 +0,0 @@
-| test.py:7 | response | externally controlled string |
-| test.py:14 | response | externally controlled string |
-| test.py:21 | response | externally controlled string |
-| test.py:36 | do_stuff_with() | externally controlled string |
-| test.py:40 | Str | externally controlled string |
-| test.py:44 | Str | externally controlled string |
-| test.py:45 | Str | externally controlled string |
-| test.py:46 | Str | externally controlled string |
diff --git a/python/ql/test/library-tests/web/twisted/Sinks.ql b/python/ql/test/library-tests/web/twisted/Sinks.ql
deleted file mode 100644
index 1045e9dda6b..00000000000
--- a/python/ql/test/library-tests/web/twisted/Sinks.ql
+++ /dev/null
@@ -1,10 +0,0 @@
-import python
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-import semmle.python.TestUtils
-
-from TaintSink sink, TaintKind kind
-where sink.sinks(kind)
-select remove_library_prefix(sink.getLocation()), sink.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/twisted/Sources.expected b/python/ql/test/library-tests/web/twisted/Sources.expected
deleted file mode 100644
index 3015951d32b..00000000000
--- a/python/ql/test/library-tests/web/twisted/Sources.expected
+++ /dev/null
@@ -1,8 +0,0 @@
-| test.py:4 | request | twisted.request.http.Request |
-| test.py:9 | request | twisted.request.http.Request |
-| test.py:16 | request | twisted.request.http.Request |
-| test.py:24 | request | twisted.request.http.Request |
-| test.py:28 | myrequest | twisted.request.http.Request |
-| test.py:31 | postrequest | twisted.request.http.Request |
-| test.py:39 | request | twisted.request.http.Request |
-| test.py:43 | request | twisted.request.http.Request |
diff --git a/python/ql/test/library-tests/web/twisted/Sources.ql b/python/ql/test/library-tests/web/twisted/Sources.ql
deleted file mode 100644
index bded6087ed2..00000000000
--- a/python/ql/test/library-tests/web/twisted/Sources.ql
+++ /dev/null
@@ -1,11 +0,0 @@
-import python
-import semmle.python.TestUtils
-
-import semmle.python.web.HttpRequest
-import semmle.python.web.HttpResponse
-import semmle.python.security.strings.Untrusted
-
-
-from TaintSource src, TaintKind kind
-where src.isSourceOf(kind)
-select remove_library_prefix(src.getLocation()), src.(ControlFlowNode).getNode().toString(), kind
diff --git a/python/ql/test/library-tests/web/twisted/Taint.ql b/python/ql/test/library-tests/web/twisted/Taint.ql
index f0a95299113..e92616b6b29 100644
--- a/python/ql/test/library-tests/web/twisted/Taint.ql
+++ b/python/ql/test/library-tests/web/twisted/Taint.ql
@@ -1,11 +1,8 @@
import python
import semmle.python.TestUtils
-
import semmle.python.web.HttpRequest
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
from TaintedNode node
-
select remove_library_prefix(node.getLocation()), node.getAstNode().toString(), node.getTaintKind()
-