diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md
index e883f885f0b..ce317236f93 100644
--- a/change-notes/1.23/analysis-cpp.md
+++ b/change-notes/1.23/analysis-cpp.md
@@ -8,13 +8,16 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
-| Query name (`query id`) | tags | Message. |
+| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | reliability, japanese-era | This query is a combination of two old queries that were identical in purpose but separate as an implementation detail. This new query replaces Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) and Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`). |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| Query name (`query id`) | Expected impact | Message. |
+| Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. |
+| Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. |
+| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | More correct results | This query now checks for the beginning date of the Reiwa era (1st May 2019). |
## Changes to QL libraries
@@ -25,3 +28,10 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.
picture of the partial flow paths from a given source. The feature is
disabled by default and can be enabled for individual configurations by
overriding `int explorationLimit()`.
+* The `DataFlow::DefinitionByReferenceNode` class now considers `f(x)` to be a
+ definition of `x` when `x` is a variable of pointer type. It no longer
+ considers deep paths such as `f(&x.myField)` to be definitions of `x`. These
+ changes are in line with the user expectations we've observed.
+* There is now a `DataFlow::localExprFlow` predicate and a
+ `TaintTracking::localExprTaint` predicate to make it easy to use the most
+ common case of local data flow and taint: from one `Expr` to another.
diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md
index a3cc5906068..697f6e01423 100644
--- a/change-notes/1.23/analysis-javascript.md
+++ b/change-notes/1.23/analysis-javascript.md
@@ -18,6 +18,7 @@
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
| Client-side cross-site scripting (`js/xss`) | More results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized. |
+| Prototype pollution (`js/prototype-pollution`) | More results | The query now highlights vulnerable uses of jQuery and Angular, and the results are shown on LGTM by default. |
## Changes to QL libraries
diff --git a/change-notes/1.23/extractor-javascript.md b/change-notes/1.23/extractor-javascript.md
new file mode 100644
index 00000000000..ed9664ce812
--- /dev/null
+++ b/change-notes/1.23/extractor-javascript.md
@@ -0,0 +1,7 @@
+[[ condition: enterprise-only ]]
+
+# Improvements to JavaScript analysis
+
+## Changes to code extraction
+
+* Asynchronous generator methods are now parsed correctly and no longer cause a spurious syntax error.
diff --git a/cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.qhelp b/cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.qhelp
new file mode 100644
index 00000000000..f009401099a
--- /dev/null
+++ b/cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.qhelp
@@ -0,0 +1,17 @@
+
+
+
+
+ When eras change, date and time conversions that rely on a hard-coded era start date need to be reviewed. Conversions relying on Japanese dates in the current era can produce an ambiguous date.
+ The values for the current Japanese era dates should be read from a source that will be updated, such as the Windows registry.
+
+
+
diff --git a/cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.ql b/cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.ql
new file mode 100644
index 00000000000..6abdb6feb8c
--- /dev/null
+++ b/cpp/ql/src/Best Practices/Magic Constants/JapaneseEraDate.ql
@@ -0,0 +1,73 @@
+/**
+ * @name Hard-coded Japanese era start date
+ * @description Japanese era changes can lead to code behaving differently. Avoid hard-coding Japanese era start dates.
+ * @kind problem
+ * @problem.severity warning
+ * @id cpp/japanese-era/exact-era-date
+ * @precision medium
+ * @tags reliability
+ * japanese-era
+ */
+
+import cpp
+import semmle.code.cpp.commons.DateTime
+
+predicate assignedYear(Struct s, YearFieldAccess year, int value) {
+ exists(Operation yearAssignment |
+ s.getAField().getAnAccess() = year and
+ yearAssignment.getAnOperand() = year and
+ yearAssignment.getAnOperand().getValue().toInt() = value
+ )
+}
+
+predicate assignedMonth(Struct s, MonthFieldAccess month, int value) {
+ exists(Operation monthAssignment |
+ s.getAField().getAnAccess() = month and
+ monthAssignment.getAnOperand() = month and
+ monthAssignment.getAnOperand().getValue().toInt() = value
+ )
+}
+
+predicate assignedDay(Struct s, DayFieldAccess day, int value) {
+ exists(Operation dayAssignment |
+ s.getAField().getAnAccess() = day and
+ dayAssignment.getAnOperand() = day and
+ dayAssignment.getAnOperand().getValue().toInt() = value
+ )
+}
+
+predicate eraDate(int year, int month, int day) {
+ year = 1989 and month = 1 and day = 8
+ or
+ year = 2019 and month = 5 and day = 1
+}
+
+
+predicate badStructInitialization(Element target, string message) {
+ exists(
+ StructLikeClass s, YearFieldAccess year, MonthFieldAccess month, DayFieldAccess day,
+ int yearValue, int monthValue, int dayValue
+ |
+ eraDate(yearValue, monthValue, dayValue) and
+ assignedYear(s, year, yearValue) and
+ assignedMonth(s, month, monthValue) and
+ assignedDay(s, day, dayValue) and
+ target = year and
+ message = "A time struct that is initialized with exact Japanese calendar era start date."
+ )
+}
+
+predicate badCall(Element target, string message) {
+ exists(Call cc, int i |
+ eraDate(cc.getArgument(i).getValue().toInt(), cc.getArgument(i + 1).getValue().toInt(),
+ cc.getArgument(i + 2).getValue().toInt()) and
+ target = cc and
+ message = "Call that appears to have hard-coded Japanese era start date as parameter."
+ )
+}
+
+from Element target, string message
+where
+ badStructInitialization(target, message) or
+ badCall(target, message)
+select target, message
diff --git a/cpp/ql/src/Critical/NewDelete.qll b/cpp/ql/src/Critical/NewDelete.qll
index 5cd7ef646d1..39b265556b0 100644
--- a/cpp/ql/src/Critical/NewDelete.qll
+++ b/cpp/ql/src/Critical/NewDelete.qll
@@ -47,7 +47,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
or
exists(Expr e |
allocExprOrIndirect(e, kind) and
- DataFlow::localFlow(DataFlow::exprNode(e), DataFlow::exprNode(rtn.getExpr()))
+ DataFlow::localExprFlow(e, rtn.getExpr())
)
)
)
diff --git a/cpp/ql/src/Critical/OverflowStatic.ql b/cpp/ql/src/Critical/OverflowStatic.ql
index a0917c47024..bd76173b6f4 100644
--- a/cpp/ql/src/Critical/OverflowStatic.ql
+++ b/cpp/ql/src/Critical/OverflowStatic.ql
@@ -95,7 +95,7 @@ class CallWithBufferSize extends FunctionCall {
int statedSizeValue() {
exists(Expr statedSizeSrc |
- DataFlow::localFlow(DataFlow::exprNode(statedSizeSrc), DataFlow::exprNode(statedSizeExpr())) and
+ DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr()) and
result = statedSizeSrc.getValue().toInt()
)
}
diff --git a/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql b/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql
index 5a8c3ee84bc..0b844bdcbf5 100644
--- a/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql
+++ b/cpp/ql/src/Likely Bugs/Conversion/LossyFunctionResultCast.ql
@@ -55,7 +55,7 @@ predicate whiteListWrapped(FunctionCall fc) {
whitelistPow(fc) or
exists(Expr e, ReturnStmt rs |
whiteListWrapped(e) and
- DataFlow::localFlow(DataFlow::exprNode(e), DataFlow::exprNode(rs.getExpr())) and
+ DataFlow::localExprFlow(e, rs.getExpr()) and
fc.getTarget() = rs.getEnclosingFunction()
)
}
diff --git a/cpp/ql/src/Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql b/cpp/ql/src/Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql
index 2a6a0f52874..fa468c74218 100644
--- a/cpp/ql/src/Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql
+++ b/cpp/ql/src/Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql
@@ -1,5 +1,5 @@
/**
- * @name Hard-coded Japanese era start date
+ * @name Hard-coded Japanese era start date in call
* @description Japanese era changes can lead to code behaving differently. Avoid hard-coding Japanese era start dates.
* @kind problem
* @problem.severity warning
@@ -7,6 +7,9 @@
* @precision medium
* @tags reliability
* japanese-era
+ * @deprecated This query is deprecated, use
+ * Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`)
+ * instead.
*/
import cpp
diff --git a/cpp/ql/src/Likely Bugs/JapaneseEra/StructWithExactEraDate.ql b/cpp/ql/src/Likely Bugs/JapaneseEra/StructWithExactEraDate.ql
index 72069d07e13..fe924954d99 100644
--- a/cpp/ql/src/Likely Bugs/JapaneseEra/StructWithExactEraDate.ql
+++ b/cpp/ql/src/Likely Bugs/JapaneseEra/StructWithExactEraDate.ql
@@ -1,5 +1,5 @@
/**
- * @name Hard-coded Japanese era start date
+ * @name Hard-coded Japanese era start date in struct
* @description Japanese era changes can lead to code behaving differently. Avoid hard-coding Japanese era start dates.
* @kind problem
* @problem.severity warning
@@ -7,6 +7,9 @@
* @precision medium
* @tags reliability
* japanese-era
+ * @deprecated This query is deprecated, use
+ * Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`)
+ * instead.
*/
import cpp
diff --git a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
index dbb4c261519..0f1a37d4813 100644
--- a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
+++ b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
@@ -4,7 +4,6 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
-import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.commons.DateTime
/**
diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql
index e41b9f7113d..ddc74cc6205 100644
--- a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql
+++ b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql
@@ -23,7 +23,7 @@ predicate isBoolean(Expr e1) {
}
predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) {
- DataFlow::localFlow(DataFlow::exprNode(func), DataFlow::exprNode(expr1)) and
+ DataFlow::localExprFlow(func, expr1) and
isBoolean(expr1.getConversion*()) and
func.getTarget() instanceof StrcpyFunction and
msg = "Return value of " + func.getTarget().getName() + " used as a Boolean."
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/PotentialBufferOverflow.ql b/cpp/ql/src/Likely Bugs/Memory Management/PotentialBufferOverflow.ql
index 99e771d0fbf..74d87182380 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/PotentialBufferOverflow.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/PotentialBufferOverflow.ql
@@ -10,8 +10,9 @@
* security
* external/cwe/cwe-676
* @deprecated This query is deprecated, use
- * Security/CWE/CWE-120/OverrunWrite.ql and
- * Security/CWE/CWE-120/OverrunWriteFloat.ql instead.
+ * Potentially overrunning write (`cpp/overrunning-write`) and
+ * Potentially overrunning write with float to string conversion
+ * (`cpp/overrunning-write-with-float) instead.
*/
import cpp
import semmle.code.cpp.commons.Buffer
diff --git a/cpp/ql/src/Likely Bugs/OO/NonVirtualDestructor.ql b/cpp/ql/src/Likely Bugs/OO/NonVirtualDestructor.ql
index 2cb6d111c9b..e4284bbd804 100644
--- a/cpp/ql/src/Likely Bugs/OO/NonVirtualDestructor.ql
+++ b/cpp/ql/src/Likely Bugs/OO/NonVirtualDestructor.ql
@@ -8,8 +8,8 @@
* @problem.severity warning
* @tags reliability
* @deprecated This query is deprecated, and replaced by
- * jsf/4.10 Classes/AV Rule 78.ql, which has far fewer false
- * positives on typical code.
+ * No virtual destructor (`cpp/jsf/av-rule-78`), which has far
+ * fewer false positives on typical code.
*/
import cpp
diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
index e45be7640bf..d5ab739f348 100644
--- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
+++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
@@ -36,12 +36,10 @@ class MallocCall extends FunctionCall
predicate terminationProblem(MallocCall malloc, string msg) {
malloc.getAllocatedSize() instanceof StrlenCall and
- not exists(DataFlow::Node def, DataFlow::Node use, FunctionCall fc, MemcpyFunction memcpy, int ix |
- DataFlow::localFlow(def, use) and
- def.asExpr() = malloc and
+ not exists(FunctionCall fc, MemcpyFunction memcpy, int ix |
+ DataFlow::localExprFlow(malloc, fc.getArgument(ix)) and
fc.getTarget() = memcpy and
- memcpy.hasArrayOutput(ix) and
- use.asExpr() = fc.getArgument(ix)
+ memcpy.hasArrayOutput(ix)
) and
msg = "This allocation does not include space to null-terminate the string."
}
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
index af343fc991f..604f3915e98 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
@@ -12,7 +12,7 @@
* external/cwe/cwe-197
* external/cwe/cwe-835
*
-*/
+ */
import cpp
import semmle.code.cpp.controlflow.Dominance
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/DataFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/DataFlow.qll
index bfb93f77bfa..3425e9b9901 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/DataFlow.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/DataFlow.qll
@@ -11,8 +11,10 @@
*
* To use global (interprocedural) data flow, extend the class
* `DataFlow::Configuration` as documented on that class. To use local
- * (intraprocedural) data flow, invoke `DataFlow::localFlow` or
- * `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`.
+ * (intraprocedural) data flow between expressions, call
+ * `DataFlow::localExprFlow`. For more general cases of local data flow, call
+ * `DataFlow::localFlow` or `DataFlow::localFlowStep` with arguments of type
+ * `DataFlow::Node`.
*/
import cpp
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking.qll b/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking.qll
index 92cd085927a..a40579adde1 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking.qll
@@ -6,6 +6,13 @@
* the information from the source is preserved at the sink. For example, taint
* propagates from `x` to `x + 100`, but it does not propagate from `x` to `x >
* 100` since we consider a single bit of information to be too little.
+ *
+ * To use global (interprocedural) taint tracking, extend the class
+ * `TaintTracking::Configuration` as documented on that class. To use local
+ * (intraprocedural) taint tracking between expressions, call
+ * `TaintTracking::localExprTaint`. For more general cases of local taint
+ * tracking, call `TaintTracking::localTaint` or
+ * `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`.
*/
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.dataflow.DataFlow2
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking2.qll
index f67a0e71100..bde6c363347 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking2.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking2.qll
@@ -1,11 +1,14 @@
/**
- * Provides classes for performing local (intra-procedural) and
- * global (inter-procedural) taint-tracking analyses.
+ * Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
+ * module. Use this class when data-flow configurations or taint-tracking
+ * configurations must depend on each other. Two classes extending
+ * `DataFlow::Configuration` should never depend on each other, but one of them
+ * should instead depend on a `DataFlow2::Configuration`, a
+ * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
+ * `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
+ * `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
*
- * We define _taint propagation_ informally to mean that a substantial part of
- * the information from the source is preserved at the sink. For example, taint
- * propagates from `x` to `x + 100`, but it does not propagate from `x` to `x >
- * 100` since we consider a single bit of information to be too little.
+ * See `semmle.code.cpp.dataflow.TaintTracking` for the full documentation.
*/
module TaintTracking2 {
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
index 9bb6a70c742..97052e80004 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
@@ -363,6 +363,7 @@ private module ImplCommon {
newtype TReturnPosition =
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
}
+
import ImplCommon
pragma[noinline]
@@ -418,7 +419,6 @@ class CallContextReturn extends CallContext, TReturn {
/** A callable tagged with a relevant return kind. */
class ReturnPosition extends TReturnPosition0 {
private DataFlowCallable c;
-
private ReturnKind kind;
ReturnPosition() { this = TReturnPosition0(c, kind) }
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
index f906f989b48..c7456c714d9 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll
@@ -496,6 +496,12 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
+/**
+ * Holds if data can flow from `e1` to `e2` in zero or more
+ * local (intra-procedural) steps.
+ */
+predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
+
/**
* Holds if the initial value of `v`, if it is a source, flows to `var`.
*/
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll
index 3130e64d7d6..74e96d8d063 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll
@@ -84,18 +84,28 @@ cached class FlowVar extends TFlowVar {
*
* In contrast to a normal "definition", which provides a new value for
* something, a partial definition is an expression that may affect a
- * value, but does not necessarily replace it entirely. For example,
- * `x.y = 1;` is a partial definition of the object `x`.
+ * value, but does not necessarily replace it entirely. For example:
+ * ```
+ * x.y = 1; // a partial definition of the object `x`.
+ * x.y.z = 1; // a partial definition of the objects `x` and `x.y`.
+ * x.setY(1); // a partial definition of the object `x`.
+ * setY(&x); // a partial definition of the object `x`.
+ * ```
*/
private module PartialDefinitions {
private newtype TPartialDefinition =
TExplicitFieldStoreQualifier(Expr qualifier, ControlFlowNode node) {
- exists(FieldAccess fa |
- isInstanceFieldWrite(fa, node) and qualifier = fa.getQualifier()
+ exists(FieldAccess fa | qualifier = fa.getQualifier() |
+ isInstanceFieldWrite(fa, node)
+ or
+ exists(PartialDefinition pd |
+ node = pd.getSubBasicBlockStart() and
+ fa = pd.getDefinedExpr()
+ )
)
} or
TExplicitCallQualifier(Expr qualifier, Call call) { qualifier = call.getQualifier() } or
- TReferenceArgument(Expr arg, VariableAccess va) { definitionByReference(va, arg) }
+ TReferenceArgument(Expr arg, VariableAccess va) { referenceArgument(va, arg) }
private predicate isInstanceFieldWrite(FieldAccess fa, ControlFlowNode node) {
not fa.getTarget().isStatic() and
@@ -116,8 +126,19 @@ private module PartialDefinitions {
predicate partiallyDefinesThis(ThisExpr e) { definedExpr = e }
+ /**
+ * Gets the subBasicBlock where this `PartialDefinition` is defined.
+ */
ControlFlowNode getSubBasicBlockStart() { result = node }
+ /**
+ * Gets the expression that is being partially defined. For example in the
+ * following code:
+ * ```
+ * x.y = 1;
+ * ```
+ * The expression `x` is being partially defined.
+ */
Expr getDefinedExpr() { result = definedExpr }
Location getLocation() {
@@ -133,18 +154,48 @@ private module PartialDefinitions {
}
/**
- * A partial definition that's a definition by reference (in the sense of the
- * `definitionByReference` predicate).
+ * A partial definition that's a definition by reference.
*/
class DefinitionByReference extends PartialDefinition, TReferenceArgument {
VariableAccess va;
- DefinitionByReference() { definitionByReference(va, definedExpr) }
+ DefinitionByReference() {
+ // `this` is not restricted in this charpred. That's because the full
+ // extent of this class includes the charpred of the superclass, which
+ // relates `this` to `definedExpr`, and `va` is functionally determined
+ // by `definedExpr`.
+ referenceArgument(va, definedExpr)
+ }
VariableAccess getVariableAccess() { result = va }
override predicate partiallyDefines(Variable v) { va = v.getAnAccess() }
}
+
+ private predicate referenceArgument(VariableAccess va, Expr argument) {
+ argument = any(Call c).getAnArgument() and
+ exists(Type argumentType |
+ argumentType = argument.getFullyConverted().getType().stripTopLevelSpecifiers()
+ |
+ argumentType instanceof ReferenceType and
+ not argumentType.(ReferenceType).getBaseType().isConst() and
+ va = argument
+ or
+ argumentType instanceof PointerType and
+ not argumentType.(PointerType).getBaseType().isConst() and
+ (
+ // f(variable)
+ va = argument
+ or
+ // f(&variable)
+ va = argument.(AddressOfExpr).getOperand()
+ or
+ // f(&array[0])
+ va.getType().getUnspecifiedType() instanceof ArrayType and
+ va = argument.(AddressOfExpr).getOperand().(ArrayExpr).getArrayBase()
+ )
+ )
+ }
}
import PartialDefinitions
private import FlowVar_internal
@@ -215,7 +266,7 @@ module FlowVar_internal {
not v instanceof Field and // Fields are interprocedural data flow, not local
reachable(sbb) and
(
- initializer(sbb.getANode(), v, _)
+ initializer(v, sbb.getANode())
or
assignmentLikeOperation(sbb, v, _, _)
or
@@ -332,7 +383,12 @@ module FlowVar_internal {
assignmentLikeOperation(node, v, _, e) and
node = sbb
or
- initializer(node, v, e) and
+ // We pick the defining `ControlFlowNode` of an `Initializer` to be its
+ // expression rather than the `Initializer` itself. That's because the
+ // `Initializer` of a `ConditionDeclExpr` is for historical reasons not
+ // part of the CFG and therefore ends up in the wrong basic block.
+ initializer(v, e) and
+ node = e and
node = sbb.getANode()
}
@@ -690,13 +746,11 @@ module FlowVar_internal {
}
/**
- * Holds if `v` is initialized by `init` to have value `assignedExpr`.
+ * Holds if `v` is initialized to have value `assignedExpr`.
*/
- predicate initializer(
- Initializer init, LocalVariable v, Expr assignedExpr)
+ predicate initializer(LocalVariable v, Expr assignedExpr)
{
- v = init.getDeclaration() and
- assignedExpr = init.getExpr()
+ assignedExpr = v.getInitializer().getExpr()
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
index e379157a603..93910382cee 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll
@@ -80,6 +80,14 @@ predicate localTaint(DataFlow::Node source, DataFlow::Node sink) {
localTaintStep*(source, sink)
}
+/**
+ * Holds if taint can flow from `e1` to `e2` in zero or more
+ * local (intra-procedural) steps.
+ */
+predicate localExprTaint(Expr e1, Expr e2) {
+ localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
+}
+
/**
* Holds if we do not propagate taint from `fromExpr` to `toExpr`
* even though `toExpr` is the AST parent of `fromExpr`.
diff --git a/cpp/ql/src/semmle/code/cpp/internal/ResolveClass.qll b/cpp/ql/src/semmle/code/cpp/internal/ResolveClass.qll
index 61cd3b2d056..73d3cb6772e 100644
--- a/cpp/ql/src/semmle/code/cpp/internal/ResolveClass.qll
+++ b/cpp/ql/src/semmle/code/cpp/internal/ResolveClass.qll
@@ -1,7 +1,9 @@
import semmle.code.cpp.Type
+/** For upgraded databases without mangled name info. */
pragma[noinline]
private string getTopLevelClassName(@usertype c) {
+ not mangled_name(_, _) and
isClass(c) and
usertypes(c, result, _) and
not namespacembrs(_, c) and // not in a namespace
@@ -9,24 +11,76 @@ private string getTopLevelClassName(@usertype c) {
not class_instantiation(c, _) // not a template instantiation
}
-/** Holds if `d` is a unique complete class named `name`. */
+/**
+ * For upgraded databases without mangled name info.
+ * Holds if `d` is a unique complete class named `name`.
+ */
pragma[noinline]
private predicate existsCompleteWithName(string name, @usertype d) {
+ not mangled_name(_, _) and
is_complete(d) and
name = getTopLevelClassName(d) and
onlyOneCompleteClassExistsWithName(name)
}
+/** For upgraded databases without mangled name info. */
pragma[noinline]
private predicate onlyOneCompleteClassExistsWithName(string name) {
+ not mangled_name(_, _) and
strictcount(@usertype c | is_complete(c) and getTopLevelClassName(c) = name) = 1
}
+/**
+ * For upgraded databases without mangled name info.
+ * Holds if `c` is an incomplete class named `name`.
+ */
+pragma[noinline]
+private predicate existsIncompleteWithName(string name, @usertype c) {
+ not mangled_name(_, _) and
+ not is_complete(c) and
+ name = getTopLevelClassName(c)
+}
+
+/**
+ * For upgraded databases without mangled name info.
+ * Holds if `c` is an incomplete class, and there exists a unique complete class `d`
+ * with the same name.
+ */
+private predicate oldHasCompleteTwin(@usertype c, @usertype d) {
+ not mangled_name(_, _) and
+ exists(string name |
+ existsIncompleteWithName(name, c) and
+ existsCompleteWithName(name, d)
+ )
+}
+
+pragma[noinline]
+private @mangledname getTopLevelClassMangledName(@usertype c) {
+ isClass(c) and
+ mangled_name(c, result) and
+ not namespacembrs(_, c) and // not in a namespace
+ not member(_, _, c) and // not in some structure
+ not class_instantiation(c, _) // not a template instantiation
+}
+
+/** Holds if `d` is a unique complete class named `name`. */
+pragma[noinline]
+private predicate existsCompleteWithMangledName(@mangledname name, @usertype d) {
+ is_complete(d) and
+ name = getTopLevelClassMangledName(d) and
+ onlyOneCompleteClassExistsWithMangledName(name)
+}
+
+pragma[noinline]
+private predicate onlyOneCompleteClassExistsWithMangledName(@mangledname name) {
+ strictcount(@usertype c | is_complete(c) and getTopLevelClassMangledName(c) = name) = 1
+}
+
/** Holds if `c` is an incomplete class named `name`. */
pragma[noinline]
-private predicate existsIncompleteWithName(string name, @usertype c) {
+private predicate existsIncompleteWithMangledName(@mangledname name, @usertype c) {
not is_complete(c) and
- name = getTopLevelClassName(c)
+ name = getTopLevelClassMangledName(c)
}
/**
@@ -34,9 +88,9 @@ private predicate existsIncompleteWithName(string name, @usertype c) {
* with the same name.
*/
private predicate hasCompleteTwin(@usertype c, @usertype d) {
- exists(string name |
- existsIncompleteWithName(name, c) and
- existsCompleteWithName(name, d)
+ exists(@mangledname name |
+ existsIncompleteWithMangledName(name, c) and
+ existsCompleteWithMangledName(name, d)
)
}
@@ -49,7 +103,11 @@ cached private module Cached {
cached @usertype resolveClass(@usertype c) {
hasCompleteTwin(c, result)
or
- (not hasCompleteTwin(c, _) and result = c)
+ oldHasCompleteTwin(c, result)
+ or
+ (not hasCompleteTwin(c, _) and
+ not oldHasCompleteTwin(c, _) and
+ result = c)
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
index e248fa0dae6..740f4812bdc 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
index 9bb6a70c742..97052e80004 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
@@ -363,6 +363,7 @@ private module ImplCommon {
newtype TReturnPosition =
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
}
+
import ImplCommon
pragma[noinline]
@@ -418,7 +419,6 @@ class CallContextReturn extends CallContext, TReturn {
/** A callable tagged with a relevant return kind. */
class ReturnPosition extends TReturnPosition0 {
private DataFlowCallable c;
-
private ReturnKind kind;
ReturnPosition() { this = TReturnPosition0(c, kind) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index e9715925432..1db97a49c03 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -178,6 +178,12 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
+/**
+ * Holds if data can flow from `e1` to `e2` in zero or more
+ * local (intra-procedural) steps.
+ */
+predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
+
/**
* A guard that validates some expression.
*
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll
index e7b21f0f6ec..650c15f189a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll
@@ -76,7 +76,6 @@ DefaultEdge defaultEdge() { result = TDefaultEdge() }
*/
class CaseEdge extends EdgeKind, TCaseEdge {
string minValue;
-
string maxValue;
CaseEdge() { this = TCaseEdge(minValue, maxValue) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll
index 2c1b43672fc..a7ca4593ac4 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll
@@ -59,7 +59,6 @@ abstract class IRVariable extends TIRVariable {
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var;
-
Language::Type type;
IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -110,9 +109,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
-
TempVariableTag tag;
-
Language::Type type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
index ea0a3f72998..43f9663d2cd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
@@ -922,7 +922,6 @@ class ConvertInstruction extends UnaryInstruction {
*/
class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class baseClass;
-
Language::Class derivedClass;
InheritanceConversionInstruction() {
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 fda04820848..1ced8ef3282 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
@@ -196,9 +196,7 @@ class MemoryOperand extends Operand {
*/
class NonPhiOperand extends Operand {
Instruction useInstr;
-
Instruction defInstr;
-
OperandTag tag;
NonPhiOperand() {
@@ -231,7 +229,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
override MemoryOperandTag tag;
-
Overlap overlap;
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
@@ -359,7 +356,6 @@ class ThisArgumentOperand extends ArgumentOperand {
*/
class PositionalArgumentOperand extends ArgumentOperand {
override PositionalArgumentOperandTag tag;
-
int argIndex;
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
@@ -413,11 +409,8 @@ class SideEffectOperand extends TypedOperand {
*/
class PhiInputOperand extends MemoryOperand, TPhiOperand {
PhiInstruction useInstr;
-
Instruction defInstr;
-
IRBlock predecessorBlock;
-
Overlap overlap;
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll
index 2c1b43672fc..a7ca4593ac4 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll
@@ -59,7 +59,6 @@ abstract class IRVariable extends TIRVariable {
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var;
-
Language::Type type;
IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -110,9 +109,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
-
TempVariableTag tag;
-
Language::Type type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
index ea0a3f72998..43f9663d2cd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
@@ -922,7 +922,6 @@ class ConvertInstruction extends UnaryInstruction {
*/
class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class baseClass;
-
Language::Class derivedClass;
InheritanceConversionInstruction() {
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 fda04820848..1ced8ef3282 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
@@ -196,9 +196,7 @@ class MemoryOperand extends Operand {
*/
class NonPhiOperand extends Operand {
Instruction useInstr;
-
Instruction defInstr;
-
OperandTag tag;
NonPhiOperand() {
@@ -231,7 +229,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
override MemoryOperandTag tag;
-
Overlap overlap;
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
@@ -359,7 +356,6 @@ class ThisArgumentOperand extends ArgumentOperand {
*/
class PositionalArgumentOperand extends ArgumentOperand {
override PositionalArgumentOperandTag tag;
-
int argIndex;
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
@@ -413,11 +409,8 @@ class SideEffectOperand extends TypedOperand {
*/
class PhiInputOperand extends MemoryOperand, TPhiOperand {
PhiInstruction useInstr;
-
Instruction defInstr;
-
IRBlock predecessorBlock;
-
Overlap overlap;
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll
index 2c1b43672fc..a7ca4593ac4 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll
@@ -59,7 +59,6 @@ abstract class IRVariable extends TIRVariable {
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var;
-
Language::Type type;
IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -110,9 +109,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
-
TempVariableTag tag;
-
Language::Type type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
index ea0a3f72998..43f9663d2cd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
@@ -922,7 +922,6 @@ class ConvertInstruction extends UnaryInstruction {
*/
class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class baseClass;
-
Language::Class derivedClass;
InheritanceConversionInstruction() {
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 fda04820848..1ced8ef3282 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
@@ -196,9 +196,7 @@ class MemoryOperand extends Operand {
*/
class NonPhiOperand extends Operand {
Instruction useInstr;
-
Instruction defInstr;
-
OperandTag tag;
NonPhiOperand() {
@@ -231,7 +229,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
override MemoryOperandTag tag;
-
Overlap overlap;
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
@@ -359,7 +356,6 @@ class ThisArgumentOperand extends ArgumentOperand {
*/
class PositionalArgumentOperand extends ArgumentOperand {
override PositionalArgumentOperandTag tag;
-
int argIndex;
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
@@ -413,11 +409,8 @@ class SideEffectOperand extends TypedOperand {
*/
class PhiInputOperand extends MemoryOperand, TPhiOperand {
PhiInstruction useInstr;
-
Instruction defInstr;
-
IRBlock predecessorBlock;
-
Overlap overlap;
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme
index 81a312e6daf..c4c27a2661b 100644
--- a/cpp/ql/src/semmlecode.cpp.dbscheme
+++ b/cpp/ql/src/semmlecode.cpp.dbscheme
@@ -705,6 +705,11 @@ usertype_uuid(
unique string uuid: string ref
);
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname
+);
+
is_pod_class(unique int id: @usertype ref);
is_standard_layout_class(unique int id: @usertype ref);
diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats
index 245b2047b8e..85160eeeac5 100644
--- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats
+++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats
@@ -116,6 +116,10 @@
4328015
+@mangledname
+533074
+
+@type_mention1699398
@@ -200,6 +204,22 @@
1685056
+@preincrexpr
+63965
+
+
+@predecrexpr
+26590
+
+
+@assignexpr
+551713
+
+
+@varaccess
+5376523
+
+@literal4374193
@@ -276,14 +296,6 @@
5401
-@preincrexpr
-63965
-
-
-@predecrexpr
-26590
-
-@conditionalexpr154429
@@ -396,10 +408,6 @@
1
-@assignexpr
-551713
-
-@assignaddexpr68305
@@ -488,10 +496,6 @@
30
-@varaccess
-5376523
-
-@thisaccess1181367
@@ -844,6 +848,14 @@
1284491
+@stmt_return
+1197363
+
+
+@stmt_block
+1398476
+
+@stmt_if524558
@@ -860,14 +872,6 @@
85508
-@stmt_return
-1197363
-
-
-@stmt_block
-1398476
-
-@stmt_end_test_while149900
@@ -936,14 +940,6 @@
3
-@ppd_plain_include
-321760
-
-
-@ppd_define
-350005
-
-@ppd_if171105
@@ -968,6 +964,14 @@
329749
+@ppd_plain_include
+321760
+
+
+@ppd_define
+350005
+
+@ppd_undef21155
@@ -1492,7 +1496,7 @@
seconds
-12182
+12669
@@ -1536,14 +1540,19 @@
12
+2
+3
+24
+
+34
-3149
+302745
-7416
+7513
@@ -1589,8 +1598,8 @@
12
-1002
-1003
+1042
+104312
@@ -1647,13 +1656,13 @@
12
-547
-548
+563
+56412
-577
-578
+620
+62112
@@ -1670,28 +1679,23 @@
12
-7684
+803623
-2662
+271134
-814
+9964
-14
+597924
-
-14
-616
-97
-
@@ -1706,7 +1710,7 @@
12
-12182
+12669
@@ -1722,17 +1726,17 @@
12
-10517
+1079623
-1653
+183534
-12
+36
@@ -2111,11 +2115,11 @@
cpu_seconds
-8437
+8450elapsed_seconds
-170
+182
@@ -2161,17 +2165,17 @@
12
-7112
+706423
-911
+98439
-413
+401
@@ -2192,7 +2196,7 @@
23
-486
+498
@@ -2208,7 +2212,7 @@
12
-24
+362
@@ -2216,38 +2220,48 @@
24
-3
-4
+4
+512
-9
-10
+10
+1112
-11
-12
+12
+1312
-21
-22
-24
-
-
-45
-46
+18
+1912
-129
-130
+23
+2412
-133
-134
+57
+58
+12
+
+
+127
+128
+12
+
+
+131
+132
+12
+
+
+237
+23812
@@ -2255,11 +2269,6 @@
24612
-
-248
-249
-12
-
@@ -2274,7 +2283,7 @@
12
-24
+362
@@ -2282,48 +2291,53 @@
24
-3
-4
+4
+512
-9
-10
+10
+1112
-11
-12
+12
+1312
-21
-22
-24
-
-
-45
-46
+17
+1812
-107
-108
+23
+2412
-119
-120
+54
+5512
-177
-178
+105
+10612
-215
-216
+114
+115
+12
+
+
+168
+169
+12
+
+
+222
+22312
@@ -23516,6 +23530,79 @@
+mangled_name
+4326447
+
+
+id
+4326447
+
+
+mangled_name
+533074
+
+
+
+
+id
+mangled_name
+
+
+12
+
+
+1
+2
+4326447
+
+
+
+
+
+
+mangled_name
+id
+
+
+12
+
+
+1
+2
+326831
+
+
+2
+3
+67771
+
+
+3
+4
+35794
+
+
+4
+8
+44998
+
+
+8
+36
+40183
+
+
+36
+8470
+17495
+
+
+
+
+
+
+
+is_pod_class1041528
@@ -32123,11 +32210,11 @@
kind
-1167
+393location
-3937292
+6150603
@@ -32171,69 +32258,69 @@
12
-4
-18
-97
+5
+28
+30
-22
-48
-85
+71
+82
+30
-48
-91
-97
+94
+255
+30
-123
-295
-97
+271
+627
+30
-341
-541
-97
+858
+1879
+30
-541
-883
-97
+2191
+3716
+30
-1163
-2188
-97
+4305
+6068
+30
-2428
-3029
-97
+7004
+11661
+30
-3265
-4616
-97
+12107
+20202
+30
-4933
-6580
-97
+21965
+29561
+30
-6933
-20444
-97
+32830
+41032
+30
-30541
-198015
-97
+44670
+145995
+30
-399017
-399018
-12
+447805
+725766
+24
@@ -32248,63 +32335,68 @@
1
-7
-97
+24
+30
-7
-14
-97
+27
+72
+30
-15
-28
-97
+77
+157
+30
-29
-47
-97
+171
+402
+30
-74
-171
-97
+422
+1083
+30
-175
-325
-97
+1179
+1862
+30
-371
-515
-97
+2201
+4268
+30
-623
-1087
-97
+4679
+6584
+30
-1127
-1577
-97
+6624
+11083
+30
-1827
-2138
-97
+11359
+12983
+30
-2219
-8862
-97
+17158
+28621
+30
-9363
-117436
-97
+29980
+88945
+30
+
+
+128315
+425042
+24
@@ -32320,37 +32412,22 @@
12
-1896838
+445058723
-762528
+8746433
-4
-367780
+6
+496205
-4
-5
-283559
-
-
-5
-9
-309310
-
-
-9
-73
-295656
-
-
-73
-110845
-21617
+6
+22445
+329167
@@ -32366,17 +32443,22 @@
12
-2811371
+459930123
-875346
+8128123
-30
-250573
+5
+498909
+
+
+5
+33
+239579
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp
new file mode 100644
index 00000000000..1ba5dada567
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/clang.cpp
@@ -0,0 +1,53 @@
+// semmle-extractor-options: --edg --clang
+
+int source();
+void sink(int); void sink(const int *); void sink(int **);
+
+struct twoIntFields {
+ int m1, m2;
+ int getFirst() { return m1; }
+};
+
+void following_pointers(
+ int sourceArray1[],
+ int cleanArray1[],
+ twoIntFields sourceStruct1,
+ twoIntFields *sourceStruct1_ptr,
+ int (*sourceFunctionPointer)())
+{
+ sink(sourceArray1); // flow
+
+ sink(sourceArray1[0]); // no flow
+ sink(*sourceArray1); // no flow
+ sink(&sourceArray1); // no flow (since sourceArray1 is really a pointer)
+
+ sink(sourceStruct1.m1); // no flow
+ sink(sourceStruct1_ptr->m1); // no flow
+ sink(sourceStruct1_ptr->getFirst()); // no flow
+
+ sourceStruct1_ptr->m1 = source();
+ sink(sourceStruct1_ptr->m1); // flow
+ sink(sourceStruct1_ptr->getFirst()); // flow [NOT DETECTED with IR]
+ sink(sourceStruct1_ptr->m2); // no flow
+ sink(sourceStruct1.m1); // no flow
+
+ twoIntFields s = { source(), source() };
+
+
+ sink(s.m2); // flow
+
+ twoIntFields sArray[1] = { { source(), source() } };
+ // TODO: fix this like above
+ sink(sArray[0].m2); // flow (AST dataflow misses this due to limitations of the analysis)
+
+ twoIntFields sSwapped = { .m2 = source(), .m1 = 0 };
+
+ sink(sSwapped.m2); // flow
+
+ sink(sourceFunctionPointer()); // no flow
+
+ int stackArray[2] = { source(), source() };
+ stackArray[0] = source();
+ sink(stackArray); // no flow
+}
+
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected
index a14cc1d0929..31217a9c75c 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected
@@ -37,25 +37,25 @@
| test.cpp:24:10:24:11 | t2 | test.cpp:23:23:23:24 | t1 |
| test.cpp:24:10:24:11 | t2 | test.cpp:24:5:24:11 | ... = ... |
| test.cpp:24:10:24:11 | t2 | test.cpp:26:8:26:9 | t1 |
-| test.cpp:430:48:430:54 | source1 | test.cpp:432:17:432:23 | source1 |
-| test.cpp:431:12:431:13 | 0 | test.cpp:432:11:432:13 | tmp |
-| test.cpp:431:12:431:13 | 0 | test.cpp:432:33:432:35 | tmp |
-| test.cpp:431:12:431:13 | 0 | test.cpp:433:8:433:10 | tmp |
-| test.cpp:432:10:432:13 | & ... | test.cpp:432:3:432:8 | call to memcpy |
-| test.cpp:432:10:432:13 | ref arg & ... | test.cpp:432:3:432:8 | call to memcpy |
-| test.cpp:432:10:432:13 | ref arg & ... | test.cpp:432:33:432:35 | tmp |
-| test.cpp:432:10:432:13 | ref arg & ... | test.cpp:433:8:433:10 | tmp |
-| test.cpp:432:17:432:23 | source1 | test.cpp:432:10:432:13 | ref arg & ... |
-| test.cpp:436:53:436:59 | source1 | test.cpp:439:17:439:23 | source1 |
-| test.cpp:436:66:436:66 | b | test.cpp:441:7:441:7 | b |
-| test.cpp:437:12:437:13 | 0 | test.cpp:438:19:438:21 | tmp |
-| test.cpp:437:12:437:13 | 0 | test.cpp:439:11:439:13 | tmp |
-| test.cpp:437:12:437:13 | 0 | test.cpp:439:33:439:35 | tmp |
-| test.cpp:437:12:437:13 | 0 | test.cpp:440:8:440:10 | tmp |
-| test.cpp:437:12:437:13 | 0 | test.cpp:442:10:442:12 | tmp |
-| test.cpp:439:10:439:13 | & ... | test.cpp:439:3:439:8 | call to memcpy |
-| test.cpp:439:10:439:13 | ref arg & ... | test.cpp:439:3:439:8 | call to memcpy |
-| test.cpp:439:10:439:13 | ref arg & ... | test.cpp:439:33:439:35 | tmp |
-| test.cpp:439:10:439:13 | ref arg & ... | test.cpp:440:8:440:10 | tmp |
-| test.cpp:439:10:439:13 | ref arg & ... | test.cpp:442:10:442:12 | tmp |
-| test.cpp:439:17:439:23 | source1 | test.cpp:439:10:439:13 | ref arg & ... |
+| test.cpp:382:48:382:54 | source1 | test.cpp:384:17:384:23 | source1 |
+| test.cpp:383:12:383:13 | 0 | test.cpp:384:11:384:13 | tmp |
+| test.cpp:383:12:383:13 | 0 | test.cpp:384:33:384:35 | tmp |
+| test.cpp:383:12:383:13 | 0 | test.cpp:385:8:385:10 | tmp |
+| test.cpp:384:10:384:13 | & ... | test.cpp:384:3:384:8 | call to memcpy |
+| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:3:384:8 | call to memcpy |
+| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:33:384:35 | tmp |
+| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:385:8:385:10 | tmp |
+| test.cpp:384:17:384:23 | source1 | test.cpp:384:10:384:13 | ref arg & ... |
+| test.cpp:388:53:388:59 | source1 | test.cpp:391:17:391:23 | source1 |
+| test.cpp:388:66:388:66 | b | test.cpp:393:7:393:7 | b |
+| test.cpp:389:12:389:13 | 0 | test.cpp:390:19:390:21 | tmp |
+| test.cpp:389:12:389:13 | 0 | test.cpp:391:11:391:13 | tmp |
+| test.cpp:389:12:389:13 | 0 | test.cpp:391:33:391:35 | tmp |
+| test.cpp:389:12:389:13 | 0 | test.cpp:392:8:392:10 | tmp |
+| test.cpp:389:12:389:13 | 0 | test.cpp:394:10:394:12 | tmp |
+| test.cpp:391:10:391:13 | & ... | test.cpp:391:3:391:8 | call to memcpy |
+| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:3:391:8 | call to memcpy |
+| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:33:391:35 | tmp |
+| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:392:8:392:10 | tmp |
+| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:394:10:394:12 | tmp |
+| test.cpp:391:17:391:23 | source1 | test.cpp:391:10:391:13 | ref arg & ... |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
index 9b8eb8ca577..6c445fb76c1 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
@@ -111,54 +111,6 @@ void local_references(int &source1, int clean1) {
}
}
-struct twoIntFields {
- int m1, m2;
- int getFirst() { return m1; }
-};
-
-void following_pointers(
- int sourceArray1[],
- int cleanArray1[],
- twoIntFields sourceStruct1,
- twoIntFields *sourceStruct1_ptr,
- int (*sourceFunctionPointer)())
-{
- sink(sourceArray1); // flow
-
- sink(sourceArray1[0]); // no flow
- sink(*sourceArray1); // no flow
- sink(&sourceArray1); // no flow (since sourceArray1 is really a pointer)
-
- sink(sourceStruct1.m1); // no flow
- sink(sourceStruct1_ptr->m1); // no flow
- sink(sourceStruct1_ptr->getFirst()); // no flow
-
- sourceStruct1_ptr->m1 = source();
- sink(sourceStruct1_ptr->m1); // flow
- sink(sourceStruct1_ptr->getFirst()); // flow [NOT DETECTED with IR]
- sink(sourceStruct1_ptr->m2); // no flow
- sink(sourceStruct1.m1); // no flow
-
- twoIntFields s = { source(), source() };
-
-
- sink(s.m2); // flow
-
- twoIntFields sArray[1] = { { source(), source() } };
- // TODO: fix this like above
- sink(sArray[0].m2); // flow (AST dataflow misses this due to limitations of the analysis)
-
- twoIntFields sSwapped = { .m2 = source(), .m1 = 0 };
-
- sink(sSwapped.m2); // flow
-
- sink(sourceFunctionPointer()); // no flow
-
- int stackArray[2] = { source(), source() };
- stackArray[0] = source();
- sink(stackArray); // no flow
-}
-
int alwaysAssignSource(int *out) {
*out = source();
return 0;
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected
index bca0bfbca69..60410aa3c0a 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected
@@ -1,4 +1,9 @@
| acrossLinkTargets.cpp:12:8:12:8 | x | acrossLinkTargets.cpp:19:27:19:32 | call to source |
+| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
+| clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source |
+| clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source |
+| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
+| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
| lambdas.cpp:14:3:14:6 | t | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:18:8:18:8 | call to operator() | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:21:3:21:6 | t | lambdas.cpp:8:10:8:15 | call to source |
@@ -19,42 +24,37 @@
| test.cpp:86:8:86:9 | i1 | test.cpp:83:7:83:8 | u2 |
| test.cpp:90:8:90:14 | source1 | test.cpp:89:28:89:34 | source1 |
| test.cpp:103:10:103:12 | ref | test.cpp:100:13:100:18 | call to source |
-| test.cpp:126:8:126:19 | sourceArray1 | test.cpp:120:9:120:20 | sourceArray1 |
-| test.cpp:137:27:137:28 | m1 | test.cpp:136:27:136:32 | call to source |
-| test.cpp:138:27:138:34 | call to getFirst | test.cpp:136:27:136:32 | call to source |
-| test.cpp:145:10:145:11 | m2 | test.cpp:142:32:142:37 | call to source |
-| test.cpp:153:17:153:18 | m2 | test.cpp:151:35:151:40 | call to source |
-| test.cpp:188:8:188:8 | y | test.cpp:186:27:186:32 | call to source |
-| test.cpp:192:8:192:8 | s | test.cpp:199:33:199:38 | call to source |
-| test.cpp:200:8:200:8 | y | test.cpp:199:33:199:38 | call to source |
-| test.cpp:205:8:205:8 | x | test.cpp:212:34:212:39 | call to source |
-| test.cpp:213:8:213:8 | y | test.cpp:212:34:212:39 | call to source |
-| test.cpp:226:8:226:8 | y | test.cpp:219:11:219:16 | call to source |
-| test.cpp:308:12:308:12 | x | test.cpp:293:14:293:19 | call to source |
-| test.cpp:314:12:314:12 | x | test.cpp:313:22:313:27 | call to source |
-| test.cpp:337:14:337:14 | x | test.cpp:353:17:353:22 | call to source |
-| test.cpp:366:7:366:7 | x | test.cpp:362:4:362:9 | call to source |
-| test.cpp:397:10:397:18 | globalVar | test.cpp:395:17:395:22 | call to source |
-| test.cpp:413:10:413:14 | field | test.cpp:407:13:407:18 | call to source |
-| test.cpp:417:10:417:14 | field | test.cpp:421:13:421:18 | call to source |
-| test.cpp:423:10:423:14 | field | test.cpp:421:13:421:18 | call to source |
-| test.cpp:433:8:433:10 | tmp | test.cpp:430:48:430:54 | source1 |
-| test.cpp:440:8:440:10 | tmp | test.cpp:436:53:436:59 | source1 |
-| test.cpp:442:10:442:12 | tmp | test.cpp:436:53:436:59 | source1 |
-| test.cpp:449:8:449:10 | tmp | test.cpp:447:7:447:9 | tmp |
-| test.cpp:456:8:456:10 | tmp | test.cpp:453:7:453:9 | tmp |
-| test.cpp:466:8:466:12 | local | test.cpp:464:7:464:11 | local |
-| test.cpp:466:8:466:12 | local | test.cpp:465:16:465:20 | ref arg local |
-| test.cpp:472:8:472:12 | local | test.cpp:470:7:470:11 | local |
-| test.cpp:472:8:472:12 | local | test.cpp:471:20:471:25 | ref arg & ... |
-| test.cpp:478:8:478:12 | local | test.cpp:476:7:476:11 | local |
-| test.cpp:478:8:478:12 | local | test.cpp:477:20:477:24 | ref arg local |
-| test.cpp:485:8:485:12 | local | test.cpp:483:7:483:11 | local |
-| test.cpp:485:8:485:12 | local | test.cpp:484:18:484:23 | ref arg & ... |
-| test.cpp:491:8:491:12 | local | test.cpp:489:7:489:11 | local |
-| test.cpp:491:8:491:12 | local | test.cpp:490:18:490:22 | ref arg local |
-| test.cpp:498:9:498:22 | (statement expression) | test.cpp:497:26:497:32 | source1 |
-| test.cpp:509:8:509:12 | local | test.cpp:497:26:497:32 | source1 |
+| test.cpp:140:8:140:8 | y | test.cpp:138:27:138:32 | call to source |
+| test.cpp:144:8:144:8 | s | test.cpp:151:33:151:38 | call to source |
+| test.cpp:152:8:152:8 | y | test.cpp:151:33:151:38 | call to source |
+| test.cpp:157:8:157:8 | x | test.cpp:164:34:164:39 | call to source |
+| test.cpp:165:8:165:8 | y | test.cpp:164:34:164:39 | call to source |
+| test.cpp:178:8:178:8 | y | test.cpp:171:11:171:16 | call to source |
+| test.cpp:260:12:260:12 | x | test.cpp:245:14:245:19 | call to source |
+| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
+| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
+| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
+| test.cpp:349:10:349:18 | globalVar | test.cpp:347:17:347:22 | call to source |
+| test.cpp:365:10:365:14 | field | test.cpp:359:13:359:18 | call to source |
+| test.cpp:369:10:369:14 | field | test.cpp:373:13:373:18 | call to source |
+| test.cpp:375:10:375:14 | field | test.cpp:373:13:373:18 | call to source |
+| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
+| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
+| test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 |
+| test.cpp:401:8:401:10 | tmp | test.cpp:399:7:399:9 | tmp |
+| test.cpp:408:8:408:10 | tmp | test.cpp:405:7:405:9 | tmp |
+| test.cpp:418:8:418:12 | local | test.cpp:416:7:416:11 | local |
+| test.cpp:418:8:418:12 | local | test.cpp:417:16:417:20 | ref arg local |
+| test.cpp:424:8:424:12 | local | test.cpp:422:7:422:11 | local |
+| test.cpp:424:8:424:12 | local | test.cpp:423:20:423:25 | ref arg & ... |
+| test.cpp:430:8:430:12 | local | test.cpp:428:7:428:11 | local |
+| test.cpp:430:8:430:12 | local | test.cpp:429:20:429:24 | ref arg local |
+| test.cpp:437:8:437:12 | local | test.cpp:435:7:435:11 | local |
+| test.cpp:437:8:437:12 | local | test.cpp:436:18:436:23 | ref arg & ... |
+| test.cpp:443:8:443:12 | local | test.cpp:441:7:441:11 | local |
+| test.cpp:443:8:443:12 | local | test.cpp:442:18:442:22 | ref arg local |
+| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
+| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
| true_upon_entry.cpp:21:8:21:8 | x | true_upon_entry.cpp:17:11:17:16 | call to source |
| true_upon_entry.cpp:29:8:29:8 | x | true_upon_entry.cpp:27:9:27:14 | call to source |
| true_upon_entry.cpp:39:8:39:8 | x | true_upon_entry.cpp:33:11:33:16 | call to source |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
index 1228f8f5816..b89b98f42d5 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected
@@ -1,3 +1,6 @@
+| clang.cpp:28:27:28:32 | clang.cpp:29:27:29:28 | AST only |
+| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
+| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |
@@ -7,28 +10,25 @@
| test.cpp:89:28:89:34 | test.cpp:92:8:92:14 | IR only |
| test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only |
| test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only |
-| test.cpp:136:27:136:32 | test.cpp:137:27:137:28 | AST only |
-| test.cpp:136:27:136:32 | test.cpp:138:27:138:34 | AST only |
-| test.cpp:147:42:147:47 | test.cpp:149:18:149:19 | IR only |
-| test.cpp:395:17:395:22 | test.cpp:397:10:397:18 | AST only |
-| test.cpp:407:13:407:18 | test.cpp:413:10:413:14 | AST only |
-| test.cpp:421:13:421:18 | test.cpp:417:10:417:14 | AST only |
-| test.cpp:421:13:421:18 | test.cpp:423:10:423:14 | AST only |
-| test.cpp:430:48:430:54 | test.cpp:433:8:433:10 | AST only |
-| test.cpp:436:53:436:59 | test.cpp:440:8:440:10 | AST only |
-| test.cpp:436:53:436:59 | test.cpp:442:10:442:12 | AST only |
-| test.cpp:447:7:447:9 | test.cpp:449:8:449:10 | AST only |
-| test.cpp:453:7:453:9 | test.cpp:456:8:456:10 | AST only |
-| test.cpp:464:7:464:11 | test.cpp:466:8:466:12 | AST only |
-| test.cpp:465:16:465:20 | test.cpp:466:8:466:12 | AST only |
-| test.cpp:470:7:470:11 | test.cpp:472:8:472:12 | AST only |
-| test.cpp:471:20:471:25 | test.cpp:472:8:472:12 | AST only |
-| test.cpp:476:7:476:11 | test.cpp:478:8:478:12 | AST only |
-| test.cpp:477:20:477:24 | test.cpp:478:8:478:12 | AST only |
-| test.cpp:483:7:483:11 | test.cpp:485:8:485:12 | AST only |
-| test.cpp:484:18:484:23 | test.cpp:485:8:485:12 | AST only |
-| test.cpp:489:7:489:11 | test.cpp:491:8:491:12 | AST only |
-| test.cpp:490:18:490:22 | test.cpp:491:8:491:12 | AST only |
+| test.cpp:347:17:347:22 | test.cpp:349:10:349:18 | AST only |
+| test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only |
+| test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only |
+| test.cpp:373:13:373:18 | test.cpp:375:10:375:14 | AST only |
+| test.cpp:382:48:382:54 | test.cpp:385:8:385:10 | AST only |
+| test.cpp:388:53:388:59 | test.cpp:392:8:392:10 | AST only |
+| test.cpp:388:53:388:59 | test.cpp:394:10:394:12 | AST only |
+| test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only |
+| test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only |
+| test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only |
+| test.cpp:417:16:417:20 | test.cpp:418:8:418:12 | AST only |
+| test.cpp:422:7:422:11 | test.cpp:424:8:424:12 | AST only |
+| test.cpp:423:20:423:25 | test.cpp:424:8:424:12 | AST only |
+| test.cpp:428:7:428:11 | test.cpp:430:8:430:12 | AST only |
+| test.cpp:429:20:429:24 | test.cpp:430:8:430:12 | AST only |
+| test.cpp:435:7:435:11 | test.cpp:437:8:437:12 | AST only |
+| test.cpp:436:18:436:23 | test.cpp:437:8:437:12 | AST only |
+| test.cpp:441:7:441:11 | test.cpp:443:8:443:12 | AST only |
+| test.cpp:442:18:442:22 | test.cpp:443:8:443:12 | AST only |
| true_upon_entry.cpp:9:11:9:16 | true_upon_entry.cpp:13:8:13:8 | IR only |
| true_upon_entry.cpp:62:11:62:16 | true_upon_entry.cpp:66:8:66:8 | IR only |
| true_upon_entry.cpp:98:11:98:16 | true_upon_entry.cpp:105:8:105:8 | IR only |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
index ad242a435a0..83ba546480f 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected
@@ -1,5 +1,10 @@
| acrossLinkTargets.cpp:12:8:12:8 | Convert: (int)... | acrossLinkTargets.cpp:19:27:19:32 | Call: call to source |
| acrossLinkTargets.cpp:12:8:12:8 | Load: x | acrossLinkTargets.cpp:19:27:19:32 | Call: call to source |
+| clang.cpp:18:8:18:19 | Convert: (const int *)... | clang.cpp:12:9:12:20 | InitializeParameter: sourceArray1 |
+| clang.cpp:18:8:18:19 | Load: sourceArray1 | clang.cpp:12:9:12:20 | InitializeParameter: sourceArray1 |
+| clang.cpp:37:10:37:11 | Load: m2 | clang.cpp:34:32:34:37 | Call: call to source |
+| clang.cpp:41:18:41:19 | Load: m2 | clang.cpp:39:42:39:47 | Call: call to source |
+| clang.cpp:45:17:45:18 | Load: m2 | clang.cpp:43:35:43:40 | Call: call to source |
| test.cpp:7:8:7:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |
@@ -15,23 +20,18 @@
| test.cpp:90:8:90:14 | Load: source1 | test.cpp:89:28:89:34 | InitializeParameter: source1 |
| test.cpp:92:8:92:14 | Load: source1 | test.cpp:89:28:89:34 | InitializeParameter: source1 |
| test.cpp:110:10:110:12 | Load: (reference dereference) | test.cpp:109:9:109:14 | Call: call to source |
-| test.cpp:126:8:126:19 | Convert: (const int *)... | test.cpp:120:9:120:20 | InitializeParameter: sourceArray1 |
-| test.cpp:126:8:126:19 | Load: sourceArray1 | test.cpp:120:9:120:20 | InitializeParameter: sourceArray1 |
-| test.cpp:145:10:145:11 | Load: m2 | test.cpp:142:32:142:37 | Call: call to source |
-| test.cpp:149:18:149:19 | Load: m2 | test.cpp:147:42:147:47 | Call: call to source |
-| test.cpp:153:17:153:18 | Load: m2 | test.cpp:151:35:151:40 | Call: call to source |
-| test.cpp:188:8:188:8 | Load: y | test.cpp:186:27:186:32 | Call: call to source |
-| test.cpp:192:8:192:8 | Load: s | test.cpp:199:33:199:38 | Call: call to source |
-| test.cpp:200:8:200:8 | Load: y | test.cpp:199:33:199:38 | Call: call to source |
-| test.cpp:205:8:205:8 | Load: x | test.cpp:212:34:212:39 | Call: call to source |
-| test.cpp:213:8:213:8 | Load: y | test.cpp:212:34:212:39 | Call: call to source |
-| test.cpp:226:8:226:8 | Load: y | test.cpp:219:11:219:16 | Call: call to source |
-| test.cpp:308:12:308:12 | Load: x | test.cpp:293:14:293:19 | Call: call to source |
-| test.cpp:314:12:314:12 | Load: x | test.cpp:313:22:313:27 | Call: call to source |
-| test.cpp:337:14:337:14 | Load: x | test.cpp:353:17:353:22 | Call: call to source |
-| test.cpp:366:7:366:7 | Load: x | test.cpp:362:4:362:9 | Call: call to source |
-| test.cpp:498:9:498:22 | CopyValue: (statement expression) | test.cpp:497:26:497:32 | InitializeParameter: source1 |
-| test.cpp:509:8:509:12 | Load: local | test.cpp:497:26:497:32 | InitializeParameter: source1 |
+| test.cpp:140:8:140:8 | Load: y | test.cpp:138:27:138:32 | Call: call to source |
+| test.cpp:144:8:144:8 | Load: s | test.cpp:151:33:151:38 | Call: call to source |
+| test.cpp:152:8:152:8 | Load: y | test.cpp:151:33:151:38 | Call: call to source |
+| test.cpp:157:8:157:8 | Load: x | test.cpp:164:34:164:39 | Call: call to source |
+| test.cpp:165:8:165:8 | Load: y | test.cpp:164:34:164:39 | Call: call to source |
+| test.cpp:178:8:178:8 | Load: y | test.cpp:171:11:171:16 | Call: call to source |
+| test.cpp:260:12:260:12 | Load: x | test.cpp:245:14:245:19 | Call: call to source |
+| test.cpp:266:12:266:12 | Load: x | test.cpp:265:22:265:27 | Call: call to source |
+| test.cpp:289:14:289:14 | Load: x | test.cpp:305:17:305:22 | Call: call to source |
+| test.cpp:318:7:318:7 | Load: x | test.cpp:314:4:314:9 | Call: call to source |
+| test.cpp:450:9:450:22 | CopyValue: (statement expression) | test.cpp:449:26:449:32 | InitializeParameter: source1 |
+| test.cpp:461:8:461:12 | Load: local | test.cpp:449:26:449:32 | InitializeParameter: source1 |
| true_upon_entry.cpp:13:8:13:8 | Load: x | true_upon_entry.cpp:9:11:9:16 | Call: call to source |
| true_upon_entry.cpp:21:8:21:8 | Load: x | true_upon_entry.cpp:17:11:17:16 | Call: call to source |
| true_upon_entry.cpp:29:8:29:8 | Load: x | true_upon_entry.cpp:27:9:27:14 | Call: call to source |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected
index 6cfc73519dd..9cffdb99e60 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected
@@ -1,20 +1,20 @@
| test.cpp:75:7:75:8 | u1 | test.cpp:76:8:76:9 | u1 |
| test.cpp:83:7:83:8 | u2 | test.cpp:84:13:84:14 | u2 |
| test.cpp:83:7:83:8 | u2 | test.cpp:85:8:85:9 | u2 |
-| test.cpp:447:7:447:9 | tmp | test.cpp:448:11:448:13 | tmp |
-| test.cpp:447:7:447:9 | tmp | test.cpp:449:8:449:10 | tmp |
-| test.cpp:453:7:453:9 | tmp | test.cpp:454:19:454:21 | tmp |
-| test.cpp:453:7:453:9 | tmp | test.cpp:455:11:455:13 | tmp |
-| test.cpp:453:7:453:9 | tmp | test.cpp:456:8:456:10 | tmp |
-| test.cpp:464:7:464:11 | local | test.cpp:465:16:465:20 | local |
-| test.cpp:464:7:464:11 | local | test.cpp:466:8:466:12 | local |
-| test.cpp:470:7:470:11 | local | test.cpp:471:21:471:25 | local |
-| test.cpp:470:7:470:11 | local | test.cpp:472:8:472:12 | local |
-| test.cpp:476:7:476:11 | local | test.cpp:477:20:477:24 | local |
-| test.cpp:476:7:476:11 | local | test.cpp:478:8:478:12 | local |
-| test.cpp:476:7:476:11 | local | test.cpp:479:9:479:13 | local |
-| test.cpp:483:7:483:11 | local | test.cpp:484:19:484:23 | local |
-| test.cpp:483:7:483:11 | local | test.cpp:485:8:485:12 | local |
-| test.cpp:489:7:489:11 | local | test.cpp:490:18:490:22 | local |
-| test.cpp:489:7:489:11 | local | test.cpp:491:8:491:12 | local |
-| test.cpp:489:7:489:11 | local | test.cpp:492:9:492:13 | local |
+| test.cpp:399:7:399:9 | tmp | test.cpp:400:11:400:13 | tmp |
+| test.cpp:399:7:399:9 | tmp | test.cpp:401:8:401:10 | tmp |
+| test.cpp:405:7:405:9 | tmp | test.cpp:406:19:406:21 | tmp |
+| test.cpp:405:7:405:9 | tmp | test.cpp:407:11:407:13 | tmp |
+| test.cpp:405:7:405:9 | tmp | test.cpp:408:8:408:10 | tmp |
+| test.cpp:416:7:416:11 | local | test.cpp:417:16:417:20 | local |
+| test.cpp:416:7:416:11 | local | test.cpp:418:8:418:12 | local |
+| test.cpp:422:7:422:11 | local | test.cpp:423:21:423:25 | local |
+| test.cpp:422:7:422:11 | local | test.cpp:424:8:424:12 | local |
+| test.cpp:428:7:428:11 | local | test.cpp:429:20:429:24 | local |
+| test.cpp:428:7:428:11 | local | test.cpp:430:8:430:12 | local |
+| test.cpp:428:7:428:11 | local | test.cpp:431:9:431:13 | local |
+| test.cpp:435:7:435:11 | local | test.cpp:436:19:436:23 | local |
+| test.cpp:435:7:435:11 | local | test.cpp:437:8:437:12 | local |
+| test.cpp:441:7:441:11 | local | test.cpp:442:18:442:22 | local |
+| test.cpp:441:7:441:11 | local | test.cpp:443:8:443:12 | local |
+| test.cpp:441:7:441:11 | local | test.cpp:444:9:444:13 | local |
diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp
index 7668db1fbbc..fd49e1e85ee 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp
@@ -129,7 +129,7 @@ public:
{
B *b = new B();
f7(b);
- sink(b->c); // flow [NOT DETECTED]
+ sink(b->c); // flow
}
class D
@@ -151,7 +151,7 @@ public:
D *d = new D(b, r());
sink(d->b); // flow x2
sink(d->b->c); // flow
- sink(b->c); // flow [NOT DETECTED]
+ sink(b->c); // flow
}
void f10()
diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp
index cdcade3f39d..8a5dcc0e509 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp
@@ -61,3 +61,34 @@ void assignBeforeCopy() {
S copy2 = s2;
sink(copy2.m1); // flow
}
+
+struct Wrapper {
+ S s;
+};
+
+void copyIntermediate() {
+ Wrapper w = { { 0, 0 } };
+ S s = w.s;
+ s.m1 = user_input();
+ sink(w.s.m1); // no flow
+}
+
+void pointerIntermediate() {
+ Wrapper w = { { 0, 0 } };
+ S *s = &w.s;
+ s->m1 = user_input();
+ sink(w.s.m1); // flow [FALSE NEGATIVE]
+}
+
+void referenceIntermediate() {
+ Wrapper w = { { 0, 0 } };
+ S &s = w.s;
+ s.m1 = user_input();
+ sink(w.s.m1); // flow [FALSE NEGATIVE]
+}
+
+void nestedAssign() {
+ Wrapper w = { { 0, 0 } };
+ w.s.m1 = user_input();
+ sink(w.s.m1); // flow
+}
diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp
index 5a6c67fa8df..31ed50283be 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp
@@ -33,8 +33,16 @@ void sink(int x)
void bar(Bar &b)
{
- sink(b.f.a()); // flow (through `b1.f.setA` and `b3.f.setA`) [NOT DETECTED]
- sink(b.f.b()); // flow (through `b2.f.setB` and `b3.f.setB`) [NOT DETECTED]
+ // The library correctly finds that the four `user_input` sources can make it
+ // to the `sink` calls, but it also finds some source/sink combinations that
+ // are impossible. Those false positives here are a consequence of how the
+ // shared data flow library overapproximates field flow. The library only
+ // tracks the head (`f`) and the length (2) of the field access path, and
+ // then it tracks that both `a_` and `b_` have followed `f` in _some_ access
+ // path somewhere in the search. That makes the library conclude that there
+ // could be flow to `b.f.a_` even when the flow was actually to `b.f.b_`.
+ sink(b.f.a()); // flow [FALSE POSITIVE through `b2.f.setB` and `b3.f.setB`]
+ sink(b.f.b()); // flow [FALSE POSITIVE through `b1.f.setA` and `b3.f.setA`]
}
void foo()
diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected
index 38aa90f8731..fadc2f15bb5 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected
@@ -24,7 +24,12 @@ edges
| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] |
| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a |
| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a |
+| A.cpp:126:5:126:5 | b [post update] [c] | A.cpp:131:8:131:8 | ref arg b [c] |
+| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | b [post update] [c] |
+| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] |
+| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c |
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] |
+| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] |
| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] |
| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | ... = ... |
| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] |
@@ -36,9 +41,11 @@ edges
| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] |
| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] |
| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] |
+| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] |
| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b |
| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] |
| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c |
+| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c |
| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b |
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] |
| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] |
@@ -96,6 +103,34 @@ edges
| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] |
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... |
| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 |
+| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] |
+| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] |
+| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] |
+| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... |
+| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] |
+| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 |
+| complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] |
+| complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] |
+| complex.cpp:44:8:44:8 | b [f, a_] | complex.cpp:44:10:44:10 | f [a_] |
+| complex.cpp:44:10:44:10 | f [a_] | complex.cpp:44:12:44:12 | call to a |
+| complex.cpp:45:8:45:8 | b [f, b_] | complex.cpp:45:10:45:10 | f [b_] |
+| complex.cpp:45:10:45:10 | f [b_] | complex.cpp:45:12:45:12 | call to b |
+| complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | complex.cpp:61:7:61:8 | b1 [f, a_] |
+| complex.cpp:55:6:55:6 | f [post update] [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] |
+| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | f [post update] [a_] |
+| complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | complex.cpp:64:7:64:8 | b2 [f, b_] |
+| complex.cpp:56:6:56:6 | f [post update] [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] |
+| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | f [post update] [b_] |
+| complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | complex.cpp:67:7:67:8 | b3 [f, a_] |
+| complex.cpp:57:6:57:6 | f [post update] [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] |
+| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | f [post update] [a_] |
+| complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | complex.cpp:67:7:67:8 | b3 [f, b_] |
+| complex.cpp:58:6:58:6 | f [post update] [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] |
+| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | f [post update] [b_] |
+| complex.cpp:61:7:61:8 | b1 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] |
+| complex.cpp:64:7:64:8 | b2 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] |
+| complex.cpp:67:7:67:8 | b3 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] |
+| complex.cpp:67:7:67:8 | b3 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] |
| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] |
| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] |
| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a |
@@ -145,9 +180,11 @@ edges
| A.cpp:75:14:75:14 | c | A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | c flows from $@ | A.cpp:73:25:73:32 | new | new |
| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new |
| A.cpp:120:16:120:16 | a | A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new |
+| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new |
| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new |
| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new |
| A.cpp:153:16:153:16 | c | A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new |
+| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new |
| A.cpp:165:26:165:29 | head | A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new |
| A.cpp:169:15:169:18 | head | A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new |
| B.cpp:9:20:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new |
@@ -157,6 +194,11 @@ edges
| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input |
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input |
| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input |
+| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
+| complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input |
+| complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input |
+| complex.cpp:45:12:45:12 | call to b | complex.cpp:56:13:56:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:56:13:56:22 | call to user_input | call to user_input |
+| complex.cpp:45:12:45:12 | call to b | complex.cpp:58:13:58:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:58:13:58:22 | call to user_input | call to user_input |
| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input |
| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input |
| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input |
diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.cpp b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.cpp
new file mode 100644
index 00000000000..4ee706a1902
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.cpp
@@ -0,0 +1,16 @@
+
+struct MyStruct
+{
+ int x;
+ struct MySubStruct {
+ int z;
+ } y;
+};
+
+void test()
+{
+ MyStruct s;
+
+ s.x = 1;
+ s.y.z = 1;
+}
diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected
new file mode 100644
index 00000000000..2ad9e47f1b1
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected
@@ -0,0 +1,3 @@
+| partialdefinitions.cpp:14:2:14:2 | partial def of s | partialdefinitions.cpp:14:2:14:2 | s | partialdefinitions.cpp:14:2:14:8 | ... = ... |
+| partialdefinitions.cpp:15:2:15:2 | partial def of s | partialdefinitions.cpp:15:2:15:2 | s | partialdefinitions.cpp:15:2:15:10 | ... = ... |
+| partialdefinitions.cpp:15:4:15:4 | partial def of y | partialdefinitions.cpp:15:4:15:4 | y | partialdefinitions.cpp:15:2:15:10 | ... = ... |
diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql
new file mode 100644
index 00000000000..db34eb16cb8
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql
@@ -0,0 +1,4 @@
+import semmle.code.cpp.dataflow.internal.FlowVar
+
+from PartialDefinition def
+select def, def.getDefinedExpr(), def.getSubBasicBlockStart()
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
index ab23866fe0e..4895cf71112 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
@@ -133,6 +133,7 @@
| taint.cpp:165:22:165:25 | {...} | taint.cpp:172:10:172:15 | buffer | |
| taint.cpp:165:22:165:25 | {...} | taint.cpp:173:8:173:13 | buffer | |
| taint.cpp:165:24:165:24 | 0 | taint.cpp:165:22:165:25 | {...} | TAINT |
+| taint.cpp:168:8:168:14 | ref arg tainted | taint.cpp:172:18:172:24 | tainted | |
| taint.cpp:170:10:170:15 | buffer | taint.cpp:170:3:170:8 | call to strcpy | |
| taint.cpp:170:10:170:15 | ref arg buffer | taint.cpp:170:3:170:8 | call to strcpy | |
| taint.cpp:170:10:170:15 | ref arg buffer | taint.cpp:171:8:171:13 | buffer | |
@@ -188,11 +189,11 @@
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
| taint.cpp:228:11:228:11 | `this` parameter in (constructor) | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | |
-| taint.cpp:228:11:228:11 | `this` parameter in (constructor) | taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | |
+| taint.cpp:228:11:228:11 | constructor init of field t [post-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
+| taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
| taint.cpp:228:11:232:2 | [...](...){...} | taint.cpp:233:7:233:7 | a | |
| taint.cpp:228:11:232:2 | {...} | taint.cpp:228:11:232:2 | [...](...){...} | |
| taint.cpp:228:17:228:17 | `this` parameter in operator() | taint.cpp:229:3:229:6 | this | |
-| taint.cpp:228:17:228:17 | `this` parameter in operator() | taint.cpp:244:3:244:6 | this | |
| taint.cpp:229:3:229:6 | this | taint.cpp:230:3:230:6 | this | |
| taint.cpp:230:3:230:6 | this | taint.cpp:231:3:231:11 | this | |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
@@ -211,11 +212,11 @@
| taint.cpp:238:7:238:12 | call to source | taint.cpp:238:3:238:14 | ... = ... | |
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
-| taint.cpp:243:11:243:11 | `this` parameter in (constructor) | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | |
| taint.cpp:243:11:243:11 | `this` parameter in (constructor) | taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | |
+| taint.cpp:243:11:243:11 | constructor init of field t [post-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
+| taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
| taint.cpp:243:11:246:2 | [...](...){...} | taint.cpp:247:2:247:2 | c | |
| taint.cpp:243:11:246:2 | {...} | taint.cpp:243:11:246:2 | [...](...){...} | |
-| taint.cpp:243:15:243:15 | `this` parameter in operator() | taint.cpp:229:3:229:6 | this | |
| taint.cpp:243:15:243:15 | `this` parameter in operator() | taint.cpp:244:3:244:6 | this | |
| taint.cpp:244:3:244:6 | this | taint.cpp:245:3:245:6 | this | |
| taint.cpp:249:11:252:2 | [...](...){...} | taint.cpp:253:2:253:2 | d | |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactDate.cpp b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/ConstructorOrMethodWithExactDate.cpp
similarity index 89%
rename from cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactDate.cpp
rename to cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/ConstructorOrMethodWithExactDate.cpp
index a1eef2e3b90..2720aa8f403 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactDate.cpp
+++ b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/ConstructorOrMethodWithExactDate.cpp
@@ -37,4 +37,7 @@ int Main()
// GOOD: method call with the same parameters in a different order (we only track year, month, day)
EraInfo * pDateTimeUtil4 = EraInfo::EraInfoFromDate(1, 2, 8, 1, 1989, L"\u5e73\u6210");
+
+ // BAD: constructor creating a EraInfo with exact Reiwa era start date
+ EraInfo * pDateTimeUtil5 = new EraInfo(2019, 5, 1);
}
\ No newline at end of file
diff --git a/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/JapaneseEraDate.expected b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/JapaneseEraDate.expected
new file mode 100644
index 00000000000..58ac64cc308
--- /dev/null
+++ b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/JapaneseEraDate.expected
@@ -0,0 +1,7 @@
+| ConstructorOrMethodWithExactDate.cpp:27:31:27:53 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
+| ConstructorOrMethodWithExactDate.cpp:30:32:30:77 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
+| ConstructorOrMethodWithExactDate.cpp:36:32:36:55 | call to EraInfoFromDate | Call that appears to have hard-coded Japanese era start date as parameter. |
+| ConstructorOrMethodWithExactDate.cpp:42:32:42:54 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
+| StructWithExactDate.cpp:31:13:31:19 | tm_year | A time struct that is initialized with exact Japanese calendar era start date. |
+| StructWithExactDate.cpp:46:8:46:12 | wYear | A time struct that is initialized with exact Japanese calendar era start date. |
+| StructWithExactDate.cpp:60:9:60:13 | wYear | A time struct that is initialized with exact Japanese calendar era start date. |
diff --git a/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/JapaneseEraDate.qlref b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/JapaneseEraDate.qlref
new file mode 100644
index 00000000000..4240387a36c
--- /dev/null
+++ b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/JapaneseEraDate.qlref
@@ -0,0 +1 @@
+Best Practices/Magic Constants/JapaneseEraDate.ql
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactDate.cpp b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/StructWithExactDate.cpp
similarity index 89%
rename from cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactDate.cpp
rename to cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/StructWithExactDate.cpp
index 9c2b9eb0640..7bbf3397ff9 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactDate.cpp
+++ b/cpp/ql/test/query-tests/Best Practices/Magic Constants/Japanese Era/StructWithExactDate.cpp
@@ -52,6 +52,13 @@ int main()
st1.wMonth = 1;
st1.wYear = 1990;
+
+ // BAD: Creation of SYSTEMTIME stuct corresponding to the beginning of Reiwa era
+ SYSTEMTIME st2;
+ st2.wDay = 1;
+ st2.wMonth = 5;
+ st2.wYear = 2019;
+
return 0;
}
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactEraDate.expected b/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactEraDate.expected
deleted file mode 100644
index 9b6c731ebd4..00000000000
--- a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactEraDate.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| ConstructorOrMethodWithExactDate.cpp:27:31:27:53 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
-| ConstructorOrMethodWithExactDate.cpp:30:32:30:77 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
-| ConstructorOrMethodWithExactDate.cpp:36:32:36:55 | call to EraInfoFromDate | Call that appears to have hard-coded Japanese era start date as parameter. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactEraDate.qlref b/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactEraDate.qlref
deleted file mode 100644
index 2e5a8969872..00000000000
--- a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/ConstructorOrMethodWithExactEraDate.qlref
+++ /dev/null
@@ -1 +0,0 @@
-Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactEraDate.expected b/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactEraDate.expected
deleted file mode 100644
index c31c9cc4d7a..00000000000
--- a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactEraDate.expected
+++ /dev/null
@@ -1,2 +0,0 @@
-| StructWithExactDate.cpp:31:13:31:19 | tm_year | A time struct that is initialized with exact Japanese calendar era start date. |
-| StructWithExactDate.cpp:46:8:46:12 | wYear | A time struct that is initialized with exact Japanese calendar era start date. |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactEraDate.qlref b/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactEraDate.qlref
deleted file mode 100644
index 443b15e6da3..00000000000
--- a/cpp/ql/test/query-tests/Likely Bugs/Japanese Era/StructWithExactEraDate.qlref
+++ /dev/null
@@ -1 +0,0 @@
-Likely Bugs/JapaneseEra/StructWithExactEraDate.ql
diff --git a/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/old.dbscheme b/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/old.dbscheme
new file mode 100644
index 00000000000..81a312e6daf
--- /dev/null
+++ b/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/old.dbscheme
@@ -0,0 +1,1904 @@
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ */
+ 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
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--mimic`
+ * 2 | `/usr/bin/gcc`
+ * 3 | `-c`
+ * 4 | f1.c
+ * 5 | f2.c
+ * 6 | f3.c
+ */
+#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
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.c
+ * 1 | f2.c
+ * 2 | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_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
+);
+
+/**
+ * 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 data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+/**
+ * The date of the snapshot.
+ */
+snapshotDate(unique date snapshotDate : date ref);
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/**
+ * Data used by the 'duplicate code' detection.
+ */
+duplicateCode(
+ unique int id : @duplication,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+/**
+ * Data used by the 'similar code' detection.
+ */
+similarCode(
+ unique int id : @similarity,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+/**
+ * Data used by the 'duplicate code' and 'similar code' detection.
+ */
+@duplication_or_similarity = @duplication | @similarity
+
+/**
+ * Data used by the 'duplicate code' and 'similar code' detection.
+ */
+#keyset[id, offset]
+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
+);
+
+/**
+ * Information about packages that provide code used during compilation.
+ * The `id` is just a unique identifier.
+ * The `namespace` is typically the name of the package manager that
+ * provided the package (e.g. "dpkg" or "yum").
+ * The `package_name` is the name of the package, and `version` is its
+ * version (as a string).
+ */
+external_packages(
+ unique int id: @external_package,
+ string namespace : string ref,
+ string package_name : string ref,
+ string version : string ref
+);
+
+/**
+ * Holds if File `fileid` was provided by package `package`.
+ */
+header_to_external_package(
+ int fileid : @file ref,
+ int package : @external_package ref
+);
+
+/*
+ * Version history
+ */
+
+svnentries(
+ unique int id : @svnentry,
+ string revision : string ref,
+ string author : string ref,
+ date revisionDate : date ref,
+ int changeSize : int ref
+)
+
+svnaffectedfiles(
+ int id : @svnentry ref,
+ int file : @file ref,
+ string action : string ref
+)
+
+svnentrymsg(
+ unique int id : @svnentry ref,
+ string message : string ref
+)
+
+svnchurn(
+ int commit : @svnentry ref,
+ int file : @file ref,
+ int addedLines : int ref,
+ int deletedLines : int ref
+)
+
+/*
+ * C++ dbscheme
+ */
+
+@location = @location_stmt | @location_expr | @location_default ;
+
+/**
+ * The location of an element that is not an expression or a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
+ */
+locations_default(
+ /** The location of an element that is not an expression or a statement. */
+ unique int id: @location_default,
+ int container: @container ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+/**
+ * The location of a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
+ */
+locations_stmt(
+ /** The location of a statement. */
+ unique int id: @location_stmt,
+ int container: @container ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+/**
+ * The location of an expression.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
+ */
+locations_expr(
+ /** The location of an expression. */
+ unique int id: @location_expr,
+ int container: @container ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: 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
+);
+
+/*
+ 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
+);
+
+fileannotations(
+ int id: @file ref,
+ int kind: int ref,
+ string name: string ref,
+ string value: string ref
+);
+
+inmacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+/*
+ case @macroinvocations.kind of
+ 1 = macro expansion
+ | 2 = other macro reference
+ ;
+*/
+macroinvocations(
+ unique int id: @macroinvocation,
+ int macro_id: @ppd_define ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+macroparent(
+ unique int id: @macroinvocation ref,
+ int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+ int id: @macroinvocation ref,
+ int location: @location ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+/*
+ case @function.kind of
+ 1 = normal
+ | 2 = constructor
+ | 3 = destructor
+ | 4 = conversion
+ | 5 = operator
+ | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk
+ ;
+*/
+functions(
+ unique int id: @function,
+ string name: string ref,
+ int kind: int ref
+);
+
+function_entry_point(int id: @function ref, unique int entry_point: @stmt ref);
+
+function_return_type(int id: @function ref, int return_type: @type ref);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+
+
+fun_decls(
+ unique int id: @fun_decl,
+ int function: @function ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+ int id: @fun_decl ref,
+ string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+ int fun_decl: @fun_decl ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+ int fun_decl: @fun_decl ref,
+ int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+ unique int fun_decl: @fun_decl ref,
+ int typedeftype_id: @usertype ref
+);
+
+param_decl_bind(
+ unique int id: @var_decl ref,
+ int index: int ref,
+ int fun_decl: @fun_decl ref
+);
+
+var_decls(
+ unique int id: @var_decl,
+ int variable: @variable ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_decl_specifiers(
+ int id: @var_decl ref,
+ string name: string ref
+)
+
+type_decls(
+ unique int id: @type_decl,
+ int type_id: @type ref,
+ int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+ unique int type_decl: @type_decl ref
+);
+
+namespace_decls(
+ unique int id: @namespace_decl,
+ int namespace_id: @namespace ref,
+ int location: @location_default ref,
+ int bodylocation: @location_default ref
+);
+
+usings(
+ unique int id: @using,
+ int element_id: @element ref,
+ int location: @location_default ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+ int parent: @element ref,
+ int child: @using ref
+);
+
+static_asserts(
+ unique int id: @static_assert,
+ int condition : @expr ref,
+ string message : string ref,
+ int location: @location_default ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+ int id: @parameter,
+ int function: @functionorblock ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+overrides(int new: @function ref, int old: @function ref);
+
+membervariables(
+ unique int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+globalvariables(
+ unique int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+enumconstants(
+ unique int id: @enumconstant,
+ int parent: @usertype ref,
+ int index: int ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/*
+ Built-in types are the fundamental types, e.g., integral, floating, and void.
+
+ case @builtintype.kind of
+ 1 = error
+ | 2 = unknown
+ | 3 = void
+ | 4 = boolean
+ | 5 = char
+ | 6 = unsigned_char
+ | 7 = signed_char
+ | 8 = short
+ | 9 = unsigned_short
+ | 10 = signed_short
+ | 11 = int
+ | 12 = unsigned_int
+ | 13 = signed_int
+ | 14 = long
+ | 15 = unsigned_long
+ | 16 = signed_long
+ | 17 = long_long
+ | 18 = unsigned_long_long
+ | 19 = signed_long_long
+ | 20 = __int8 // Microsoft-specific
+ | 21 = __int16 // Microsoft-specific
+ | 22 = __int32 // Microsoft-specific
+ | 23 = __int64 // Microsoft-specific
+ | 24 = float
+ | 25 = double
+ | 26 = long_double
+ | 27 = _Complex_float // C99-specific
+ | 28 = _Complex_double // C99-specific
+ | 29 = _Complex_long double // C99-specific
+ | 30 = _Imaginary_float // C99-specific
+ | 31 = _Imaginary_double // C99-specific
+ | 32 = _Imaginary_long_double // C99-specific
+ | 33 = wchar_t // Microsoft-specific
+ | 34 = decltype_nullptr // C++11
+ | 35 = __int128
+ | 36 = unsigned___int128
+ | 37 = signed___int128
+ | 38 = __float128
+ | 39 = _Complex___float128
+ | 40 = _Decimal32
+ | 41 = _Decimal64
+ | 42 = _Decimal128
+ | 43 = char16_t
+ | 44 = char32_t
+ | 45 = _Float32
+ | 46 = _Float32x
+ | 47 = _Float64
+ | 48 = _Float64x
+ | 49 = _Float128
+ | 50 = _Float128x
+ ;
+*/
+builtintypes(
+ unique int id: @builtintype,
+ string name: string ref,
+ int kind: int ref,
+ int size: int ref,
+ int sign: int ref,
+ int alignment: int ref
+);
+
+/*
+ Derived types are types that are directly derived from existing types and
+ point to, refer to, transform type data to return a new type.
+
+ case @derivedtype.kind of
+ 1 = pointer
+ | 2 = reference
+ | 3 = type_with_specifiers
+ | 4 = array
+ | 5 = gnu_vector
+ | 6 = routineptr
+ | 7 = routinereference
+ | 8 = rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+ | 10 = block
+ ;
+*/
+derivedtypes(
+ unique int id: @derivedtype,
+ string name: string ref,
+ int kind: int ref,
+ int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+ int size: int ref,
+ int alignment: int ref);
+
+arraysizes(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref,
+ int bytesize: int ref,
+ int alignment: int ref
+);
+
+typedefbase(
+ unique int id: @usertype ref,
+ int type_id: @type ref
+);
+
+decltypes(
+ unique int id: @decltype,
+ int expr: @expr ref,
+ int base_type: @type ref,
+ boolean parentheses_would_change_meaning: boolean ref
+);
+
+/*
+ case @usertype.kind of
+ 1 = struct
+ | 2 = class
+ | 3 = union
+ | 4 = enum
+ | 5 = typedef
+ | 6 = template
+ | 7 = template_parameter
+ | 8 = template_template_parameter
+ | 9 = proxy_class // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+ | 13 = scoped_enum
+ ;
+*/
+usertypes(
+ unique int id: @usertype,
+ string name: string ref,
+ int kind: int ref
+);
+
+usertypesize(
+ unique int id: @usertype ref,
+ int size: int ref,
+ int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+ unique int id: @usertype ref,
+ unique string uuid: string ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+class_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+
+is_proxy_class_for(
+ unique int id: @usertype ref,
+ unique int templ_param_id: @usertype ref
+);
+
+type_mentions(
+ unique int id: @type_mention,
+ int type_id: @type ref,
+ int location: @location ref,
+ // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there.
+ int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+ unique int to: @function ref,
+ int from: @function ref
+);
+function_template_argument(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+ unique int to: @variable ref,
+ int from: @variable ref
+);
+variable_template_argument(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+
+/*
+ Fixed point types
+ precision(1) = short, precision(2) = default, precision(3) = long
+ is_unsigned(1) = unsigned is_unsigned(2) = signed
+ is_fract_type(1) = declared with _Fract
+ saturating(1) = declared with _Sat
+*/
+/* TODO
+fixedpointtypes(
+ unique int id: @fixedpointtype,
+ int precision: int ref,
+ int is_unsigned: int ref,
+ int is_fract_type: int ref,
+ int saturating: int ref);
+*/
+
+routinetypes(
+ unique int id: @routinetype,
+ int return_type: @type ref
+);
+
+routinetypeargs(
+ int routine: @routinetype ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+ptrtomembers(
+ unique int id: @ptrtomember,
+ int type_id: @type ref,
+ int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+ "public",
+ "protected",
+ "private",
+
+ "const",
+ "volatile",
+ "static",
+
+ "pure",
+ "virtual",
+ "sealed", // Microsoft
+ "__interface", // Microsoft
+ "inline",
+ "explicit",
+
+ "near", // near far extension
+ "far", // near far extension
+ "__ptr32", // Microsoft
+ "__ptr64", // Microsoft
+ "__sptr", // Microsoft
+ "__uptr", // Microsoft
+ "dllimport", // Microsoft
+ "dllexport", // Microsoft
+ "thread", // Microsoft
+ "naked", // Microsoft
+ "microsoft_inline", // Microsoft
+ "forceinline", // Microsoft
+ "selectany", // Microsoft
+ "nothrow", // Microsoft
+ "novtable", // Microsoft
+ "noreturn", // Microsoft
+ "noinline", // Microsoft
+ "noalias", // Microsoft
+ "restrict", // Microsoft
+*/
+
+specifiers(
+ unique int id: @specifier,
+ unique string str: string ref
+);
+
+typespecifiers(
+ int type_id: @type ref,
+ int spec_id: @specifier ref
+);
+
+funspecifiers(
+ int func_id: @function ref,
+ int spec_id: @specifier ref
+);
+
+varspecifiers(
+ int var_id: @accessible ref,
+ int spec_id: @specifier ref
+);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ string name: string ref,
+ string name_space: string ref,
+ int location: @location_default ref
+);
+
+case @attribute.kind of
+ 0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+ unique int id: @attribute_arg,
+ int kind: int ref,
+ int attribute: @attribute ref,
+ int index: int ref,
+ int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+ 0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+;
+
+attribute_arg_value(
+ unique int arg: @attribute_arg ref,
+ string value: string ref
+);
+attribute_arg_type(
+ unique int arg: @attribute_arg ref,
+ int type_id: @type ref
+);
+attribute_arg_name(
+ unique int arg: @attribute_arg ref,
+ string name: string ref
+);
+
+typeattributes(
+ int type_id: @type ref,
+ int spec_id: @attribute ref
+);
+
+funcattributes(
+ int func_id: @function ref,
+ int spec_id: @attribute ref
+);
+
+varattributes(
+ int var_id: @accessible ref,
+ int spec_id: @attribute ref
+);
+
+stmtattributes(
+ int stmt_id: @stmt ref,
+ int spec_id: @attribute ref
+);
+
+@type = @builtintype
+ | @derivedtype
+ | @usertype
+ /* TODO | @fixedpointtype */
+ | @routinetype
+ | @ptrtomember
+ | @decltype;
+
+unspecifiedtype(
+ unique int type_id: @type ref,
+ int unspecified_type_id: @type ref
+);
+
+member(
+ int parent: @type ref,
+ int index: int ref,
+ int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+ unique int child: @enclosingfunction_child ref,
+ int parent: @function ref
+);
+
+derivations(
+ unique int derivation: @derivation,
+ int sub: @type ref,
+ int index: int ref,
+ int super: @type ref,
+ int location: @location_default ref
+);
+
+derspecifiers(
+ int der_id: @derivation ref,
+ int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+ unique int der_id: @derivation ref,
+ int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+ int sub: @usertype ref,
+ int super: @usertype ref,
+ int offset: int ref
+);
+
+frienddecls(
+ unique int id: @frienddecl,
+ int type_id: @type ref,
+ int decl_id: @declaration ref,
+ int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+ | @declaredtype
+ | @variable
+ | @enumconstant
+ | @frienddecl;
+
+@member = @membervariable
+ | @function
+ | @declaredtype
+ | @enumconstant;
+
+@locatable = @diagnostic
+ | @declaration
+ | @ppd_include
+ | @ppd_define
+ | @macroinvocation
+ /*| @funcall*/
+ | @xmllocatable
+ | @attribute
+ | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+ | @file
+ | @folder
+ | @specifier
+ | @type
+ | @expr
+ | @namespace
+ | @initialiser
+ | @stmt
+ | @derivation
+ | @comment
+ | @preprocdirect
+ | @fun_decl
+ | @var_decl
+ | @type_decl
+ | @namespace_decl
+ | @using
+ | @namequalifier
+ | @specialnamequalifyingelement
+ | @static_assert
+ | @type_mention
+ | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+ unique int id: @comment,
+ string contents: string ref,
+ int location: @location_default ref
+);
+
+commentbinding(
+ int id: @comment ref,
+ int element: @element ref
+);
+
+exprconv(
+ int converted: @expr ref,
+ unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ unique int destructor_call: @routineexpr ref
+);
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref
+);
+
+namespace_inline(
+ unique int id: @namespace ref
+);
+
+namespacembrs(
+ int parentid: @namespace ref,
+ unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+ int expr_id: @expr ref,
+ int child_index: int ref,
+ int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+ | @const_cast
+ | @dynamic_cast
+ | @reinterpret_cast
+ | @static_cast
+ ;
+
+/*
+case @conversion.kind of
+ 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion // conversion to 'bool'
+| 2 = @base_class_conversion // a derived-to-base conversion
+| 3 = @derived_class_conversion // a base-to-derived conversion
+| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+ unique int expr_id: @cast ref,
+ int kind: int ref
+);
+
+/*
+case @funbindexpr.kind of
+ 0 = @normal_call // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call // a call whose target is only found by ADL
+;
+*/
+iscall(unique int caller: @funbindexpr ref, int kind: int ref);
+
+numtemplatearguments(
+ unique int expr_id: @expr ref,
+ int num: int ref
+);
+
+specialnamequalifyingelements(
+ unique int id: @specialnamequalifyingelement,
+ unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+ | @specialnamequalifyingelement
+ | @usertype;
+
+namequalifiers(
+ unique int id: @namequalifier,
+ unique int qualifiableelement: @namequalifiableelement ref,
+ int qualifyingelement: @namequalifyingelement ref,
+ int location: @location_default ref
+);
+
+varbind(
+ int expr: @varbindexpr ref,
+ int var: @accessible ref
+);
+
+funbind(
+ int expr: @funbindexpr ref,
+ int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+ | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+ | @delete_expr
+ | @delete_array_expr;
+
+/*
+ case @allocator.form of
+ 0 = plain
+ | 1 = alignment
+ ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+ unique int expr: @any_new_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/*
+ case @deallocator.form of
+ 0 = plain
+ | 1 = size
+ | 2 = alignment
+ | 3 = size_and_alignment
+ ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+ unique int expr: @new_or_delete_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+ unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+ unique int cond: @conditionalexpr ref,
+ int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+ unique int cond: @conditionalexpr ref,
+ int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+ unique int cond: @conditionalexpr ref,
+ int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+ unique int id: @value,
+ string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+ unique int id: @value ref,
+ string text: string ref
+);
+
+valuebind(
+ int val: @value ref,
+ unique int expr: @expr ref
+);
+
+fieldoffsets(
+ unique int id: @variable ref,
+ int byteoffset: int ref,
+ int bitoffset: int ref
+);
+
+bitfield(
+ unique int id: @variable ref,
+ int bits: int ref,
+ int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+ int member: @expr ref,
+ int prefix: @expr ref
+);
+*/
+
+/*
+ kind(1) = mbrcallexpr
+ kind(2) = mbrptrcallexpr
+ kind(3) = mbrptrmbrcallexpr
+ kind(4) = ptrmbrptrmbrcallexpr
+ kind(5) = mbrreadexpr // x.y
+ kind(6) = mbrptrreadexpr // p->y
+ kind(7) = mbrptrmbrreadexpr // x.*pm
+ kind(8) = mbrptrmbrptrreadexpr // x->*pm
+ kind(9) = staticmbrreadexpr // static x.y
+ kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+ int member: @expr ref,
+ int kind: int ref
+);
+*/
+
+initialisers(
+ unique int init: @initialiser,
+ int var: @accessible ref,
+ unique int expr: @expr ref,
+ int location: @location_expr ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+ int exp: @expr ref,
+ int ancestor: @element ref
+);
+
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int location: @location_expr ref
+);
+
+/*
+ case @value.category of
+ 1 = prval
+ | 2 = xval
+ | 3 = lval
+ ;
+*/
+expr_types(
+ int id: @expr ref,
+ int typeid: @type ref,
+ int value_category: int ref
+);
+
+case @expr.kind of
+ 1 = @errorexpr
+| 2 = @address_of // & AddressOfExpr
+| 3 = @reference_to // ReferenceToExpr (implicit?)
+| 4 = @indirect // * PointerDereferenceExpr
+| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+| 8 = @array_to_pointer // (???)
+| 9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+| 11 = @assume // Microsoft
+| 12 = @parexpr
+| 13 = @arithnegexpr
+| 14 = @unaryplusexpr
+| 15 = @complementexpr
+| 16 = @notexpr
+| 17 = @conjugation // GNU ~ operator
+| 18 = @realpartexpr // GNU __real
+| 19 = @imagpartexpr // GNU __imag
+| 20 = @postincrexpr
+| 21 = @postdecrexpr
+| 22 = @preincrexpr
+| 23 = @predecrexpr
+| 24 = @conditionalexpr
+| 25 = @addexpr
+| 26 = @subexpr
+| 27 = @mulexpr
+| 28 = @divexpr
+| 29 = @remexpr
+| 30 = @jmulexpr // C99 mul imaginary
+| 31 = @jdivexpr // C99 div imaginary
+| 32 = @fjaddexpr // C99 add real + imaginary
+| 33 = @jfaddexpr // C99 add imaginary + real
+| 34 = @fjsubexpr // C99 sub real - imaginary
+| 35 = @jfsubexpr // C99 sub imaginary - real
+| 36 = @paddexpr // pointer add (pointer + int or int + pointer)
+| 37 = @psubexpr // pointer sub (pointer - integer)
+| 38 = @pdiffexpr // difference between two pointers
+| 39 = @lshiftexpr
+| 40 = @rshiftexpr
+| 41 = @andexpr
+| 42 = @orexpr
+| 43 = @xorexpr
+| 44 = @eqexpr
+| 45 = @neexpr
+| 46 = @gtexpr
+| 47 = @ltexpr
+| 48 = @geexpr
+| 49 = @leexpr
+| 50 = @minexpr // GNU minimum
+| 51 = @maxexpr // GNU maximum
+| 52 = @assignexpr
+| 53 = @assignaddexpr
+| 54 = @assignsubexpr
+| 55 = @assignmulexpr
+| 56 = @assigndivexpr
+| 57 = @assignremexpr
+| 58 = @assignlshiftexpr
+| 59 = @assignrshiftexpr
+| 60 = @assignandexpr
+| 61 = @assignorexpr
+| 62 = @assignxorexpr
+| 63 = @assignpaddexpr // assign pointer add
+| 64 = @assignpsubexpr // assign pointer sub
+| 65 = @andlogicalexpr
+| 66 = @orlogicalexpr
+| 67 = @commaexpr
+| 68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ... 69 @objc_subscriptexpr deprecated
+// ... 70 @cmdaccess deprecated
+// ...
+| 73 = @virtfunptrexpr
+| 74 = @callexpr
+// ... 75 @msgexpr_normal deprecated
+// ... 76 @msgexpr_super deprecated
+// ... 77 @atselectorexpr deprecated
+// ... 78 @atprotocolexpr deprecated
+| 79 = @vastartexpr
+| 80 = @vaargexpr
+| 81 = @vaendexpr
+| 82 = @vacopyexpr
+// ... 83 @atencodeexpr deprecated
+| 84 = @varaccess
+| 85 = @thisaccess
+// ... 86 @objc_box_expr deprecated
+| 87 = @new_expr
+| 88 = @delete_expr
+| 89 = @throw_expr
+| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+| 91 = @braced_init_list
+| 92 = @type_id
+| 93 = @runtime_sizeof
+| 94 = @runtime_alignof
+| 95 = @sizeof_pack
+| 96 = @expr_stmt // GNU extension
+| 97 = @routineexpr
+| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+| 99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+;
+
+new_allocated_type(
+ unique int expr: @new_expr ref,
+ int type_id: @type ref
+);
+
+new_array_allocated_type(
+ unique int expr: @new_array_expr ref,
+ int type_id: @type ref
+);
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union.
+ */
+#keyset[aggregate, field]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array.
+ */
+#keyset[aggregate, element_index]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref
+);
+
+@ctorinit = @ctordirectinit
+ | @ctorvirtualinit
+ | @ctorfieldinit
+ | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+ | @dtorvirtualdestruct
+ | @dtorfielddestruct;
+
+
+condition_decl_bind(
+ unique int expr: @condition_decl ref,
+ unique int decl: @declaration ref
+);
+
+typeid_bind(
+ unique int expr: @type_id ref,
+ int type_id: @type ref
+);
+
+uuidof_bind(
+ unique int expr: @uuidof ref,
+ int type_id: @type ref
+);
+
+@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof;
+
+sizeof_bind(
+ unique int expr: @runtime_sizeof_or_alignof ref,
+ int type_id: @type ref
+);
+
+code_block(
+ unique int block: @literal ref,
+ unique int routine: @function ref
+);
+
+lambdas(
+ unique int expr: @lambdaexpr ref,
+ string default_capture: string ref,
+ boolean has_explicit_return_type: boolean ref
+);
+
+lambda_capture(
+ unique int id: @lambdacapture,
+ int lambda: @lambdaexpr ref,
+ int index: int ref,
+ int field: @membervariable ref,
+ boolean captured_by_reference: boolean ref,
+ boolean is_implicit: boolean ref,
+ int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+ | @new_expr
+ | @delete_expr
+ | @delete_array_expr
+ | @ctordirectinit
+ | @ctorvirtualinit
+ | @ctordelegatinginit
+ | @dtordirectdestruct
+ | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+fold(
+ int expr: @foldexpr ref,
+ string operator: string ref,
+ boolean is_left_fold: boolean ref
+);
+
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int location: @location_stmt ref
+);
+
+case @stmt.kind of
+ 1 = @stmt_expr
+| 2 = @stmt_if
+| 3 = @stmt_while
+| 4 = @stmt_goto
+| 5 = @stmt_label
+| 6 = @stmt_return
+| 7 = @stmt_block
+| 8 = @stmt_end_test_while // do { ... } while ( ... )
+| 9 = @stmt_for
+| 10 = @stmt_switch_case
+| 11 = @stmt_switch
+| 13 = @stmt_asm // "asm" statement or the body of an asm function
+| 15 = @stmt_try_block
+| 16 = @stmt_microsoft_try // Microsoft
+| 17 = @stmt_decl
+| 18 = @stmt_set_vla_size // C99
+| 19 = @stmt_vla_decl // C99
+| 25 = @stmt_assigned_goto // GNU
+| 26 = @stmt_empty
+| 27 = @stmt_continue
+| 28 = @stmt_break
+| 29 = @stmt_range_based_for // C++11
+// ... 30 @stmt_at_autoreleasepool_block deprecated
+// ... 31 @stmt_objc_for_in deprecated
+// ... 32 @stmt_at_synchronized deprecated
+| 33 = @stmt_handler
+// ... 34 @stmt_finally_end deprecated
+| 35 = @stmt_constexpr_if
+;
+
+type_vla(
+ int type_id: @type ref,
+ int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+ int var: @variable ref,
+ int decl: @stmt_vla_decl ref
+);
+
+if_then(
+ unique int if_stmt: @stmt_if ref,
+ int then_id: @stmt ref
+);
+
+if_else(
+ unique int if_stmt: @stmt_if ref,
+ int else_id: @stmt ref
+);
+
+constexpr_if_then(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int then_id: @stmt ref
+);
+
+constexpr_if_else(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int else_id: @stmt ref
+);
+
+while_body(
+ unique int while_stmt: @stmt_while ref,
+ int body_id: @stmt ref
+);
+
+do_body(
+ unique int do_stmt: @stmt_end_test_while ref,
+ int body_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+ int switch_stmt: @stmt_switch ref,
+ int index: int ref,
+ int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+ unique int switch_stmt: @stmt_switch ref,
+ int body_id: @stmt ref
+);
+
+for_initialization(
+ unique int for_stmt: @stmt_for ref,
+ int init_id: @stmt ref
+);
+
+for_condition(
+ unique int for_stmt: @stmt_for ref,
+ int condition_id: @expr ref
+);
+
+for_update(
+ unique int for_stmt: @stmt_for ref,
+ int update_id: @expr ref
+);
+
+for_body(
+ unique int for_stmt: @stmt_for ref,
+ int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+ unique int id: @stmt ref,
+ int index: int ref,
+ int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+successors(
+ int from: @cfgnode ref,
+ int to: @cfgnode ref
+);
+
+truecond(
+ unique int from: @cfgnode ref,
+ int to: @cfgnode ref
+);
+
+falsecond(
+ unique int from: @cfgnode ref,
+ int to: @cfgnode ref
+);
+
+stmt_decl_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl_entry: @element ref
+);
+
+@functionorblock = @function | @stmt_block;
+
+blockscope(
+ unique int block: @stmt_block ref,
+ int enclosing: @functionorblock ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+ unique int id: @jumporlabel ref,
+ string str: string ref,
+ int target: @stmt ref
+);
+
+preprocdirects(
+ unique int id: @preprocdirect,
+ int kind: int ref,
+ int location: @location_default ref
+);
+case @preprocdirect.kind of
+ 0 = @ppd_if
+| 1 = @ppd_ifdef
+| 2 = @ppd_ifndef
+| 3 = @ppd_elif
+| 4 = @ppd_else
+| 5 = @ppd_endif
+| 6 = @ppd_plain_include
+| 7 = @ppd_define
+| 8 = @ppd_undef
+| 9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
+
+preprocpair(
+ int begin : @ppd_branch ref,
+ int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+ unique int id: @preprocdirect ref,
+ string head: string ref,
+ string body: string ref
+);
+
+includes(
+ unique int id: @ppd_include ref,
+ int included: @file ref
+);
+
+link_targets(
+ unique int id: @link_target,
+ int binary: @file ref
+);
+
+link_parent(
+ int element : @element ref,
+ int link_target : @link_target ref
+);
+
+/* 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;
diff --git a/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/semmlecode.cpp.dbscheme b/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/semmlecode.cpp.dbscheme
new file mode 100644
index 00000000000..c4c27a2661b
--- /dev/null
+++ b/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/semmlecode.cpp.dbscheme
@@ -0,0 +1,1909 @@
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ */
+ 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
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--mimic`
+ * 2 | `/usr/bin/gcc`
+ * 3 | `-c`
+ * 4 | f1.c
+ * 5 | f2.c
+ * 6 | f3.c
+ */
+#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
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.c
+ * 1 | f2.c
+ * 2 | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_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
+);
+
+/**
+ * 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 data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+/**
+ * The date of the snapshot.
+ */
+snapshotDate(unique date snapshotDate : date ref);
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/**
+ * Data used by the 'duplicate code' detection.
+ */
+duplicateCode(
+ unique int id : @duplication,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+/**
+ * Data used by the 'similar code' detection.
+ */
+similarCode(
+ unique int id : @similarity,
+ string relativePath : string ref,
+ int equivClass : int ref
+);
+
+/**
+ * Data used by the 'duplicate code' and 'similar code' detection.
+ */
+@duplication_or_similarity = @duplication | @similarity
+
+/**
+ * Data used by the 'duplicate code' and 'similar code' detection.
+ */
+#keyset[id, offset]
+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
+);
+
+/**
+ * Information about packages that provide code used during compilation.
+ * The `id` is just a unique identifier.
+ * The `namespace` is typically the name of the package manager that
+ * provided the package (e.g. "dpkg" or "yum").
+ * The `package_name` is the name of the package, and `version` is its
+ * version (as a string).
+ */
+external_packages(
+ unique int id: @external_package,
+ string namespace : string ref,
+ string package_name : string ref,
+ string version : string ref
+);
+
+/**
+ * Holds if File `fileid` was provided by package `package`.
+ */
+header_to_external_package(
+ int fileid : @file ref,
+ int package : @external_package ref
+);
+
+/*
+ * Version history
+ */
+
+svnentries(
+ unique int id : @svnentry,
+ string revision : string ref,
+ string author : string ref,
+ date revisionDate : date ref,
+ int changeSize : int ref
+)
+
+svnaffectedfiles(
+ int id : @svnentry ref,
+ int file : @file ref,
+ string action : string ref
+)
+
+svnentrymsg(
+ unique int id : @svnentry ref,
+ string message : string ref
+)
+
+svnchurn(
+ int commit : @svnentry ref,
+ int file : @file ref,
+ int addedLines : int ref,
+ int deletedLines : int ref
+)
+
+/*
+ * C++ dbscheme
+ */
+
+@location = @location_stmt | @location_expr | @location_default ;
+
+/**
+ * The location of an element that is not an expression or a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
+ */
+locations_default(
+ /** The location of an element that is not an expression or a statement. */
+ unique int id: @location_default,
+ int container: @container ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+/**
+ * The location of a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
+ */
+locations_stmt(
+ /** The location of a statement. */
+ unique int id: @location_stmt,
+ int container: @container ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+/**
+ * The location of an expression.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
+ */
+locations_expr(
+ /** The location of an expression. */
+ unique int id: @location_expr,
+ int container: @container ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: 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
+);
+
+/*
+ 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
+);
+
+fileannotations(
+ int id: @file ref,
+ int kind: int ref,
+ string name: string ref,
+ string value: string ref
+);
+
+inmacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+/*
+ case @macroinvocations.kind of
+ 1 = macro expansion
+ | 2 = other macro reference
+ ;
+*/
+macroinvocations(
+ unique int id: @macroinvocation,
+ int macro_id: @ppd_define ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+macroparent(
+ unique int id: @macroinvocation ref,
+ int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+ int id: @macroinvocation ref,
+ int location: @location ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+/*
+ case @function.kind of
+ 1 = normal
+ | 2 = constructor
+ | 3 = destructor
+ | 4 = conversion
+ | 5 = operator
+ | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk
+ ;
+*/
+functions(
+ unique int id: @function,
+ string name: string ref,
+ int kind: int ref
+);
+
+function_entry_point(int id: @function ref, unique int entry_point: @stmt ref);
+
+function_return_type(int id: @function ref, int return_type: @type ref);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+
+
+fun_decls(
+ unique int id: @fun_decl,
+ int function: @function ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+ int id: @fun_decl ref,
+ string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+ int fun_decl: @fun_decl ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+ int fun_decl: @fun_decl ref,
+ int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+ unique int fun_decl: @fun_decl ref,
+ int typedeftype_id: @usertype ref
+);
+
+param_decl_bind(
+ unique int id: @var_decl ref,
+ int index: int ref,
+ int fun_decl: @fun_decl ref
+);
+
+var_decls(
+ unique int id: @var_decl,
+ int variable: @variable ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_decl_specifiers(
+ int id: @var_decl ref,
+ string name: string ref
+)
+
+type_decls(
+ unique int id: @type_decl,
+ int type_id: @type ref,
+ int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+ unique int type_decl: @type_decl ref
+);
+
+namespace_decls(
+ unique int id: @namespace_decl,
+ int namespace_id: @namespace ref,
+ int location: @location_default ref,
+ int bodylocation: @location_default ref
+);
+
+usings(
+ unique int id: @using,
+ int element_id: @element ref,
+ int location: @location_default ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+ int parent: @element ref,
+ int child: @using ref
+);
+
+static_asserts(
+ unique int id: @static_assert,
+ int condition : @expr ref,
+ string message : string ref,
+ int location: @location_default ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+ int id: @parameter,
+ int function: @functionorblock ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+overrides(int new: @function ref, int old: @function ref);
+
+membervariables(
+ unique int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+globalvariables(
+ unique int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+enumconstants(
+ unique int id: @enumconstant,
+ int parent: @usertype ref,
+ int index: int ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/*
+ Built-in types are the fundamental types, e.g., integral, floating, and void.
+
+ case @builtintype.kind of
+ 1 = error
+ | 2 = unknown
+ | 3 = void
+ | 4 = boolean
+ | 5 = char
+ | 6 = unsigned_char
+ | 7 = signed_char
+ | 8 = short
+ | 9 = unsigned_short
+ | 10 = signed_short
+ | 11 = int
+ | 12 = unsigned_int
+ | 13 = signed_int
+ | 14 = long
+ | 15 = unsigned_long
+ | 16 = signed_long
+ | 17 = long_long
+ | 18 = unsigned_long_long
+ | 19 = signed_long_long
+ | 20 = __int8 // Microsoft-specific
+ | 21 = __int16 // Microsoft-specific
+ | 22 = __int32 // Microsoft-specific
+ | 23 = __int64 // Microsoft-specific
+ | 24 = float
+ | 25 = double
+ | 26 = long_double
+ | 27 = _Complex_float // C99-specific
+ | 28 = _Complex_double // C99-specific
+ | 29 = _Complex_long double // C99-specific
+ | 30 = _Imaginary_float // C99-specific
+ | 31 = _Imaginary_double // C99-specific
+ | 32 = _Imaginary_long_double // C99-specific
+ | 33 = wchar_t // Microsoft-specific
+ | 34 = decltype_nullptr // C++11
+ | 35 = __int128
+ | 36 = unsigned___int128
+ | 37 = signed___int128
+ | 38 = __float128
+ | 39 = _Complex___float128
+ | 40 = _Decimal32
+ | 41 = _Decimal64
+ | 42 = _Decimal128
+ | 43 = char16_t
+ | 44 = char32_t
+ | 45 = _Float32
+ | 46 = _Float32x
+ | 47 = _Float64
+ | 48 = _Float64x
+ | 49 = _Float128
+ | 50 = _Float128x
+ ;
+*/
+builtintypes(
+ unique int id: @builtintype,
+ string name: string ref,
+ int kind: int ref,
+ int size: int ref,
+ int sign: int ref,
+ int alignment: int ref
+);
+
+/*
+ Derived types are types that are directly derived from existing types and
+ point to, refer to, transform type data to return a new type.
+
+ case @derivedtype.kind of
+ 1 = pointer
+ | 2 = reference
+ | 3 = type_with_specifiers
+ | 4 = array
+ | 5 = gnu_vector
+ | 6 = routineptr
+ | 7 = routinereference
+ | 8 = rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+ | 10 = block
+ ;
+*/
+derivedtypes(
+ unique int id: @derivedtype,
+ string name: string ref,
+ int kind: int ref,
+ int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+ int size: int ref,
+ int alignment: int ref);
+
+arraysizes(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref,
+ int bytesize: int ref,
+ int alignment: int ref
+);
+
+typedefbase(
+ unique int id: @usertype ref,
+ int type_id: @type ref
+);
+
+decltypes(
+ unique int id: @decltype,
+ int expr: @expr ref,
+ int base_type: @type ref,
+ boolean parentheses_would_change_meaning: boolean ref
+);
+
+/*
+ case @usertype.kind of
+ 1 = struct
+ | 2 = class
+ | 3 = union
+ | 4 = enum
+ | 5 = typedef
+ | 6 = template
+ | 7 = template_parameter
+ | 8 = template_template_parameter
+ | 9 = proxy_class // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+ | 13 = scoped_enum
+ ;
+*/
+usertypes(
+ unique int id: @usertype,
+ string name: string ref,
+ int kind: int ref
+);
+
+usertypesize(
+ unique int id: @usertype ref,
+ int size: int ref,
+ int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+ unique int id: @usertype ref,
+ unique string uuid: string ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+class_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+
+is_proxy_class_for(
+ unique int id: @usertype ref,
+ unique int templ_param_id: @usertype ref
+);
+
+type_mentions(
+ unique int id: @type_mention,
+ int type_id: @type ref,
+ int location: @location ref,
+ // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there.
+ int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+ unique int to: @function ref,
+ int from: @function ref
+);
+function_template_argument(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+ unique int to: @variable ref,
+ int from: @variable ref
+);
+variable_template_argument(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+
+/*
+ Fixed point types
+ precision(1) = short, precision(2) = default, precision(3) = long
+ is_unsigned(1) = unsigned is_unsigned(2) = signed
+ is_fract_type(1) = declared with _Fract
+ saturating(1) = declared with _Sat
+*/
+/* TODO
+fixedpointtypes(
+ unique int id: @fixedpointtype,
+ int precision: int ref,
+ int is_unsigned: int ref,
+ int is_fract_type: int ref,
+ int saturating: int ref);
+*/
+
+routinetypes(
+ unique int id: @routinetype,
+ int return_type: @type ref
+);
+
+routinetypeargs(
+ int routine: @routinetype ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+ptrtomembers(
+ unique int id: @ptrtomember,
+ int type_id: @type ref,
+ int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+ "public",
+ "protected",
+ "private",
+
+ "const",
+ "volatile",
+ "static",
+
+ "pure",
+ "virtual",
+ "sealed", // Microsoft
+ "__interface", // Microsoft
+ "inline",
+ "explicit",
+
+ "near", // near far extension
+ "far", // near far extension
+ "__ptr32", // Microsoft
+ "__ptr64", // Microsoft
+ "__sptr", // Microsoft
+ "__uptr", // Microsoft
+ "dllimport", // Microsoft
+ "dllexport", // Microsoft
+ "thread", // Microsoft
+ "naked", // Microsoft
+ "microsoft_inline", // Microsoft
+ "forceinline", // Microsoft
+ "selectany", // Microsoft
+ "nothrow", // Microsoft
+ "novtable", // Microsoft
+ "noreturn", // Microsoft
+ "noinline", // Microsoft
+ "noalias", // Microsoft
+ "restrict", // Microsoft
+*/
+
+specifiers(
+ unique int id: @specifier,
+ unique string str: string ref
+);
+
+typespecifiers(
+ int type_id: @type ref,
+ int spec_id: @specifier ref
+);
+
+funspecifiers(
+ int func_id: @function ref,
+ int spec_id: @specifier ref
+);
+
+varspecifiers(
+ int var_id: @accessible ref,
+ int spec_id: @specifier ref
+);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ string name: string ref,
+ string name_space: string ref,
+ int location: @location_default ref
+);
+
+case @attribute.kind of
+ 0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+ unique int id: @attribute_arg,
+ int kind: int ref,
+ int attribute: @attribute ref,
+ int index: int ref,
+ int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+ 0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+;
+
+attribute_arg_value(
+ unique int arg: @attribute_arg ref,
+ string value: string ref
+);
+attribute_arg_type(
+ unique int arg: @attribute_arg ref,
+ int type_id: @type ref
+);
+attribute_arg_name(
+ unique int arg: @attribute_arg ref,
+ string name: string ref
+);
+
+typeattributes(
+ int type_id: @type ref,
+ int spec_id: @attribute ref
+);
+
+funcattributes(
+ int func_id: @function ref,
+ int spec_id: @attribute ref
+);
+
+varattributes(
+ int var_id: @accessible ref,
+ int spec_id: @attribute ref
+);
+
+stmtattributes(
+ int stmt_id: @stmt ref,
+ int spec_id: @attribute ref
+);
+
+@type = @builtintype
+ | @derivedtype
+ | @usertype
+ /* TODO | @fixedpointtype */
+ | @routinetype
+ | @ptrtomember
+ | @decltype;
+
+unspecifiedtype(
+ unique int type_id: @type ref,
+ int unspecified_type_id: @type ref
+);
+
+member(
+ int parent: @type ref,
+ int index: int ref,
+ int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+ unique int child: @enclosingfunction_child ref,
+ int parent: @function ref
+);
+
+derivations(
+ unique int derivation: @derivation,
+ int sub: @type ref,
+ int index: int ref,
+ int super: @type ref,
+ int location: @location_default ref
+);
+
+derspecifiers(
+ int der_id: @derivation ref,
+ int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+ unique int der_id: @derivation ref,
+ int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+ int sub: @usertype ref,
+ int super: @usertype ref,
+ int offset: int ref
+);
+
+frienddecls(
+ unique int id: @frienddecl,
+ int type_id: @type ref,
+ int decl_id: @declaration ref,
+ int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+ | @declaredtype
+ | @variable
+ | @enumconstant
+ | @frienddecl;
+
+@member = @membervariable
+ | @function
+ | @declaredtype
+ | @enumconstant;
+
+@locatable = @diagnostic
+ | @declaration
+ | @ppd_include
+ | @ppd_define
+ | @macroinvocation
+ /*| @funcall*/
+ | @xmllocatable
+ | @attribute
+ | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+ | @file
+ | @folder
+ | @specifier
+ | @type
+ | @expr
+ | @namespace
+ | @initialiser
+ | @stmt
+ | @derivation
+ | @comment
+ | @preprocdirect
+ | @fun_decl
+ | @var_decl
+ | @type_decl
+ | @namespace_decl
+ | @using
+ | @namequalifier
+ | @specialnamequalifyingelement
+ | @static_assert
+ | @type_mention
+ | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+ unique int id: @comment,
+ string contents: string ref,
+ int location: @location_default ref
+);
+
+commentbinding(
+ int id: @comment ref,
+ int element: @element ref
+);
+
+exprconv(
+ int converted: @expr ref,
+ unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ unique int destructor_call: @routineexpr ref
+);
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref
+);
+
+namespace_inline(
+ unique int id: @namespace ref
+);
+
+namespacembrs(
+ int parentid: @namespace ref,
+ unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+ int expr_id: @expr ref,
+ int child_index: int ref,
+ int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+ | @const_cast
+ | @dynamic_cast
+ | @reinterpret_cast
+ | @static_cast
+ ;
+
+/*
+case @conversion.kind of
+ 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion // conversion to 'bool'
+| 2 = @base_class_conversion // a derived-to-base conversion
+| 3 = @derived_class_conversion // a base-to-derived conversion
+| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+ unique int expr_id: @cast ref,
+ int kind: int ref
+);
+
+/*
+case @funbindexpr.kind of
+ 0 = @normal_call // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call // a call whose target is only found by ADL
+;
+*/
+iscall(unique int caller: @funbindexpr ref, int kind: int ref);
+
+numtemplatearguments(
+ unique int expr_id: @expr ref,
+ int num: int ref
+);
+
+specialnamequalifyingelements(
+ unique int id: @specialnamequalifyingelement,
+ unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+ | @specialnamequalifyingelement
+ | @usertype;
+
+namequalifiers(
+ unique int id: @namequalifier,
+ unique int qualifiableelement: @namequalifiableelement ref,
+ int qualifyingelement: @namequalifyingelement ref,
+ int location: @location_default ref
+);
+
+varbind(
+ int expr: @varbindexpr ref,
+ int var: @accessible ref
+);
+
+funbind(
+ int expr: @funbindexpr ref,
+ int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+ | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+ | @delete_expr
+ | @delete_array_expr;
+
+/*
+ case @allocator.form of
+ 0 = plain
+ | 1 = alignment
+ ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+ unique int expr: @any_new_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/*
+ case @deallocator.form of
+ 0 = plain
+ | 1 = size
+ | 2 = alignment
+ | 3 = size_and_alignment
+ ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+ unique int expr: @new_or_delete_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+ unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+ unique int cond: @conditionalexpr ref,
+ int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+ unique int cond: @conditionalexpr ref,
+ int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+ unique int cond: @conditionalexpr ref,
+ int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+ unique int id: @value,
+ string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+ unique int id: @value ref,
+ string text: string ref
+);
+
+valuebind(
+ int val: @value ref,
+ unique int expr: @expr ref
+);
+
+fieldoffsets(
+ unique int id: @variable ref,
+ int byteoffset: int ref,
+ int bitoffset: int ref
+);
+
+bitfield(
+ unique int id: @variable ref,
+ int bits: int ref,
+ int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+ int member: @expr ref,
+ int prefix: @expr ref
+);
+*/
+
+/*
+ kind(1) = mbrcallexpr
+ kind(2) = mbrptrcallexpr
+ kind(3) = mbrptrmbrcallexpr
+ kind(4) = ptrmbrptrmbrcallexpr
+ kind(5) = mbrreadexpr // x.y
+ kind(6) = mbrptrreadexpr // p->y
+ kind(7) = mbrptrmbrreadexpr // x.*pm
+ kind(8) = mbrptrmbrptrreadexpr // x->*pm
+ kind(9) = staticmbrreadexpr // static x.y
+ kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+ int member: @expr ref,
+ int kind: int ref
+);
+*/
+
+initialisers(
+ unique int init: @initialiser,
+ int var: @accessible ref,
+ unique int expr: @expr ref,
+ int location: @location_expr ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+ int exp: @expr ref,
+ int ancestor: @element ref
+);
+
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int location: @location_expr ref
+);
+
+/*
+ case @value.category of
+ 1 = prval
+ | 2 = xval
+ | 3 = lval
+ ;
+*/
+expr_types(
+ int id: @expr ref,
+ int typeid: @type ref,
+ int value_category: int ref
+);
+
+case @expr.kind of
+ 1 = @errorexpr
+| 2 = @address_of // & AddressOfExpr
+| 3 = @reference_to // ReferenceToExpr (implicit?)
+| 4 = @indirect // * PointerDereferenceExpr
+| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+| 8 = @array_to_pointer // (???)
+| 9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+| 11 = @assume // Microsoft
+| 12 = @parexpr
+| 13 = @arithnegexpr
+| 14 = @unaryplusexpr
+| 15 = @complementexpr
+| 16 = @notexpr
+| 17 = @conjugation // GNU ~ operator
+| 18 = @realpartexpr // GNU __real
+| 19 = @imagpartexpr // GNU __imag
+| 20 = @postincrexpr
+| 21 = @postdecrexpr
+| 22 = @preincrexpr
+| 23 = @predecrexpr
+| 24 = @conditionalexpr
+| 25 = @addexpr
+| 26 = @subexpr
+| 27 = @mulexpr
+| 28 = @divexpr
+| 29 = @remexpr
+| 30 = @jmulexpr // C99 mul imaginary
+| 31 = @jdivexpr // C99 div imaginary
+| 32 = @fjaddexpr // C99 add real + imaginary
+| 33 = @jfaddexpr // C99 add imaginary + real
+| 34 = @fjsubexpr // C99 sub real - imaginary
+| 35 = @jfsubexpr // C99 sub imaginary - real
+| 36 = @paddexpr // pointer add (pointer + int or int + pointer)
+| 37 = @psubexpr // pointer sub (pointer - integer)
+| 38 = @pdiffexpr // difference between two pointers
+| 39 = @lshiftexpr
+| 40 = @rshiftexpr
+| 41 = @andexpr
+| 42 = @orexpr
+| 43 = @xorexpr
+| 44 = @eqexpr
+| 45 = @neexpr
+| 46 = @gtexpr
+| 47 = @ltexpr
+| 48 = @geexpr
+| 49 = @leexpr
+| 50 = @minexpr // GNU minimum
+| 51 = @maxexpr // GNU maximum
+| 52 = @assignexpr
+| 53 = @assignaddexpr
+| 54 = @assignsubexpr
+| 55 = @assignmulexpr
+| 56 = @assigndivexpr
+| 57 = @assignremexpr
+| 58 = @assignlshiftexpr
+| 59 = @assignrshiftexpr
+| 60 = @assignandexpr
+| 61 = @assignorexpr
+| 62 = @assignxorexpr
+| 63 = @assignpaddexpr // assign pointer add
+| 64 = @assignpsubexpr // assign pointer sub
+| 65 = @andlogicalexpr
+| 66 = @orlogicalexpr
+| 67 = @commaexpr
+| 68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ... 69 @objc_subscriptexpr deprecated
+// ... 70 @cmdaccess deprecated
+// ...
+| 73 = @virtfunptrexpr
+| 74 = @callexpr
+// ... 75 @msgexpr_normal deprecated
+// ... 76 @msgexpr_super deprecated
+// ... 77 @atselectorexpr deprecated
+// ... 78 @atprotocolexpr deprecated
+| 79 = @vastartexpr
+| 80 = @vaargexpr
+| 81 = @vaendexpr
+| 82 = @vacopyexpr
+// ... 83 @atencodeexpr deprecated
+| 84 = @varaccess
+| 85 = @thisaccess
+// ... 86 @objc_box_expr deprecated
+| 87 = @new_expr
+| 88 = @delete_expr
+| 89 = @throw_expr
+| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+| 91 = @braced_init_list
+| 92 = @type_id
+| 93 = @runtime_sizeof
+| 94 = @runtime_alignof
+| 95 = @sizeof_pack
+| 96 = @expr_stmt // GNU extension
+| 97 = @routineexpr
+| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+| 99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+;
+
+new_allocated_type(
+ unique int expr: @new_expr ref,
+ int type_id: @type ref
+);
+
+new_array_allocated_type(
+ unique int expr: @new_array_expr ref,
+ int type_id: @type ref
+);
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union.
+ */
+#keyset[aggregate, field]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array.
+ */
+#keyset[aggregate, element_index]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref
+);
+
+@ctorinit = @ctordirectinit
+ | @ctorvirtualinit
+ | @ctorfieldinit
+ | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+ | @dtorvirtualdestruct
+ | @dtorfielddestruct;
+
+
+condition_decl_bind(
+ unique int expr: @condition_decl ref,
+ unique int decl: @declaration ref
+);
+
+typeid_bind(
+ unique int expr: @type_id ref,
+ int type_id: @type ref
+);
+
+uuidof_bind(
+ unique int expr: @uuidof ref,
+ int type_id: @type ref
+);
+
+@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof;
+
+sizeof_bind(
+ unique int expr: @runtime_sizeof_or_alignof ref,
+ int type_id: @type ref
+);
+
+code_block(
+ unique int block: @literal ref,
+ unique int routine: @function ref
+);
+
+lambdas(
+ unique int expr: @lambdaexpr ref,
+ string default_capture: string ref,
+ boolean has_explicit_return_type: boolean ref
+);
+
+lambda_capture(
+ unique int id: @lambdacapture,
+ int lambda: @lambdaexpr ref,
+ int index: int ref,
+ int field: @membervariable ref,
+ boolean captured_by_reference: boolean ref,
+ boolean is_implicit: boolean ref,
+ int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+ | @new_expr
+ | @delete_expr
+ | @delete_array_expr
+ | @ctordirectinit
+ | @ctorvirtualinit
+ | @ctordelegatinginit
+ | @dtordirectdestruct
+ | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+fold(
+ int expr: @foldexpr ref,
+ string operator: string ref,
+ boolean is_left_fold: boolean ref
+);
+
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int location: @location_stmt ref
+);
+
+case @stmt.kind of
+ 1 = @stmt_expr
+| 2 = @stmt_if
+| 3 = @stmt_while
+| 4 = @stmt_goto
+| 5 = @stmt_label
+| 6 = @stmt_return
+| 7 = @stmt_block
+| 8 = @stmt_end_test_while // do { ... } while ( ... )
+| 9 = @stmt_for
+| 10 = @stmt_switch_case
+| 11 = @stmt_switch
+| 13 = @stmt_asm // "asm" statement or the body of an asm function
+| 15 = @stmt_try_block
+| 16 = @stmt_microsoft_try // Microsoft
+| 17 = @stmt_decl
+| 18 = @stmt_set_vla_size // C99
+| 19 = @stmt_vla_decl // C99
+| 25 = @stmt_assigned_goto // GNU
+| 26 = @stmt_empty
+| 27 = @stmt_continue
+| 28 = @stmt_break
+| 29 = @stmt_range_based_for // C++11
+// ... 30 @stmt_at_autoreleasepool_block deprecated
+// ... 31 @stmt_objc_for_in deprecated
+// ... 32 @stmt_at_synchronized deprecated
+| 33 = @stmt_handler
+// ... 34 @stmt_finally_end deprecated
+| 35 = @stmt_constexpr_if
+;
+
+type_vla(
+ int type_id: @type ref,
+ int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+ int var: @variable ref,
+ int decl: @stmt_vla_decl ref
+);
+
+if_then(
+ unique int if_stmt: @stmt_if ref,
+ int then_id: @stmt ref
+);
+
+if_else(
+ unique int if_stmt: @stmt_if ref,
+ int else_id: @stmt ref
+);
+
+constexpr_if_then(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int then_id: @stmt ref
+);
+
+constexpr_if_else(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int else_id: @stmt ref
+);
+
+while_body(
+ unique int while_stmt: @stmt_while ref,
+ int body_id: @stmt ref
+);
+
+do_body(
+ unique int do_stmt: @stmt_end_test_while ref,
+ int body_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+ int switch_stmt: @stmt_switch ref,
+ int index: int ref,
+ int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+ unique int switch_stmt: @stmt_switch ref,
+ int body_id: @stmt ref
+);
+
+for_initialization(
+ unique int for_stmt: @stmt_for ref,
+ int init_id: @stmt ref
+);
+
+for_condition(
+ unique int for_stmt: @stmt_for ref,
+ int condition_id: @expr ref
+);
+
+for_update(
+ unique int for_stmt: @stmt_for ref,
+ int update_id: @expr ref
+);
+
+for_body(
+ unique int for_stmt: @stmt_for ref,
+ int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+ unique int id: @stmt ref,
+ int index: int ref,
+ int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+successors(
+ int from: @cfgnode ref,
+ int to: @cfgnode ref
+);
+
+truecond(
+ unique int from: @cfgnode ref,
+ int to: @cfgnode ref
+);
+
+falsecond(
+ unique int from: @cfgnode ref,
+ int to: @cfgnode ref
+);
+
+stmt_decl_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl_entry: @element ref
+);
+
+@functionorblock = @function | @stmt_block;
+
+blockscope(
+ unique int block: @stmt_block ref,
+ int enclosing: @functionorblock ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+ unique int id: @jumporlabel ref,
+ string str: string ref,
+ int target: @stmt ref
+);
+
+preprocdirects(
+ unique int id: @preprocdirect,
+ int kind: int ref,
+ int location: @location_default ref
+);
+case @preprocdirect.kind of
+ 0 = @ppd_if
+| 1 = @ppd_ifdef
+| 2 = @ppd_ifndef
+| 3 = @ppd_elif
+| 4 = @ppd_else
+| 5 = @ppd_endif
+| 6 = @ppd_plain_include
+| 7 = @ppd_define
+| 8 = @ppd_undef
+| 9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
+
+preprocpair(
+ int begin : @ppd_branch ref,
+ int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+ unique int id: @preprocdirect ref,
+ string head: string ref,
+ string body: string ref
+);
+
+includes(
+ unique int id: @ppd_include ref,
+ int included: @file ref
+);
+
+link_targets(
+ unique int id: @link_target,
+ int binary: @file ref
+);
+
+link_parent(
+ int element : @element ref,
+ int link_target : @link_target ref
+);
+
+/* 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;
diff --git a/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/upgrade.properties b/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/upgrade.properties
new file mode 100644
index 00000000000..e07968876ca
--- /dev/null
+++ b/cpp/upgrades/81a312e6dafdffb650e1c7e3dc02cc37505e2505/upgrade.properties
@@ -0,0 +1,3 @@
+description: Add name mangling table
+compatibility: partial
+
diff --git a/csharp/ql/src/Language Abuse/UselessUpcast.ql b/csharp/ql/src/Language Abuse/UselessUpcast.ql
index df2775494b7..932f14d09c6 100644
--- a/csharp/ql/src/Language Abuse/UselessUpcast.ql
+++ b/csharp/ql/src/Language Abuse/UselessUpcast.ql
@@ -75,7 +75,6 @@ private class ConstructorCall extends Call {
/** An explicit upcast. */
class ExplicitUpcast extends ExplicitCast {
ValueOrRefType src;
-
ValueOrRefType dest;
ExplicitUpcast() {
diff --git a/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql b/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql
index ba7a9d55754..6c0d4e1a708 100644
--- a/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql
+++ b/csharp/ql/src/Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql
@@ -19,7 +19,6 @@ import semmle.code.csharp.commons.ComparisonTest
/** A comparison of an index variable with the length of an array. */
class IndexGuard extends ComparisonTest {
VariableAccess indexAccess;
-
Variable array;
IndexGuard() {
diff --git a/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql b/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql
index c098cfc8d64..caa36fe89d2 100644
--- a/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql
+++ b/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql
@@ -30,11 +30,8 @@ class NestedForConditions extends SC::StructuralComparisonConfiguration {
/** A nested `for` statement that shares the same iteration variable as an outer `for` statement. */
class NestedForLoopSameVariable extends ForStmt {
ForStmt outer;
-
Variable iteration;
-
MutatorOperation innerUpdate;
-
MutatorOperation outerUpdate;
NestedForLoopSameVariable() {
diff --git a/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll b/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll
index 30ff5a8d9a2..a2c6d482c1c 100644
--- a/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll
+++ b/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll
@@ -6,7 +6,6 @@ import csharp
*/
class Package extends XMLElement {
string name;
-
Version version;
Package() {
diff --git a/csharp/ql/src/semmle/code/cil/CallableReturns.qll b/csharp/ql/src/semmle/code/cil/CallableReturns.qll
index 1efef31e03c..ee60713b801 100644
--- a/csharp/ql/src/semmle/code/cil/CallableReturns.qll
+++ b/csharp/ql/src/semmle/code/cil/CallableReturns.qll
@@ -28,6 +28,7 @@ private module Cached {
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExpr().getType())
}
}
+
import Cached
pragma[noinline]
diff --git a/csharp/ql/src/semmle/code/cil/DataFlow.qll b/csharp/ql/src/semmle/code/cil/DataFlow.qll
index d5e7f6139e0..a01ecab5e3b 100644
--- a/csharp/ql/src/semmle/code/cil/DataFlow.qll
+++ b/csharp/ql/src/semmle/code/cil/DataFlow.qll
@@ -204,6 +204,7 @@ module DefUse {
exists(VariableUpdate vu | def = vu.getSource() | variableUpdateUse(target, vu, use))
}
}
+
private import DefUse
abstract library class VariableUpdate extends Instruction {
diff --git a/csharp/ql/src/semmle/code/cil/Method.qll b/csharp/ql/src/semmle/code/cil/Method.qll
index 455459e9918..40aeb78b173 100644
--- a/csharp/ql/src/semmle/code/cil/Method.qll
+++ b/csharp/ql/src/semmle/code/cil/Method.qll
@@ -85,9 +85,7 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
override Location getLocation() { result = Element.super.getLocation() }
- override Location getALocation() {
- cil_method_location(this.getSourceDeclaration(), result)
- }
+ override Location getALocation() { cil_method_location(this.getSourceDeclaration(), result) }
override Parameter getRawParameter(int n) { cil_parameter(result, this, n, _) }
diff --git a/csharp/ql/src/semmle/code/cil/Stubs.qll b/csharp/ql/src/semmle/code/cil/Stubs.qll
index dc3d47654eb..d2a0fe736a0 100644
--- a/csharp/ql/src/semmle/code/cil/Stubs.qll
+++ b/csharp/ql/src/semmle/code/cil/Stubs.qll
@@ -40,6 +40,7 @@ private module Cached {
exists(mi.getAnInstruction())
}
}
+
private import Cached
predicate assemblyIsStub = assemblyIsStubImpl/1;
diff --git a/csharp/ql/src/semmle/code/cil/Type.qll b/csharp/ql/src/semmle/code/cil/Type.qll
index 635c097e588..9d6cbecf1ef 100644
--- a/csharp/ql/src/semmle/code/cil/Type.qll
+++ b/csharp/ql/src/semmle/code/cil/Type.qll
@@ -57,9 +57,7 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
qualifier = this.getParent().getQualifiedName()
}
- override Location getALocation() {
- cil_type_location(this.getSourceDeclaration(), result)
- }
+ override Location getALocation() { cil_type_location(this.getSourceDeclaration(), result) }
/** Holds if this type is a class. */
predicate isClass() { cil_class(this) }
diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll
index faa6b04dd55..14a88830ad2 100644
--- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll
+++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll
@@ -175,7 +175,6 @@ private newtype TAnnotatedType =
/** A type with additional information. */
class AnnotatedType extends TAnnotatedType {
Type type;
-
Annotations::TypeAnnotations annotations;
AnnotatedType() { this = TAnnotatedTypeNullability(type, annotations) }
diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll
index 7297275c7f6..63667018f1e 100644
--- a/csharp/ql/src/semmle/code/csharp/Assignable.qll
+++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll
@@ -154,7 +154,6 @@ class AssignableWrite extends AssignableAccess {
*/
private class RefArg extends AssignableAccess {
private Expr call;
-
private int position;
RefArg() {
@@ -379,8 +378,10 @@ module AssignableInternal {
)
}
}
+
import Cached
}
+
private import AssignableInternal
/**
@@ -526,7 +527,6 @@ module AssignableDefinitions {
*/
class TupleAssignmentDefinition extends AssignableDefinition, TTupleAssignmentDefinition {
AssignExpr ae;
-
Expr leaf;
TupleAssignmentDefinition() { this = TTupleAssignmentDefinition(ae, leaf) }
diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll
index d31623bd283..a18df55226e 100644
--- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll
+++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll
@@ -372,4 +372,5 @@ private module Cached {
)
}
}
+
import Cached
diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll
index 98f9e6db361..bdd28d8a0af 100644
--- a/csharp/ql/src/semmle/code/csharp/Type.qll
+++ b/csharp/ql/src/semmle/code/csharp/Type.qll
@@ -949,7 +949,6 @@ class TupleType extends ValueType, @tuple_type {
*/
class TypeMention extends @type_mention {
Type type;
-
@type_mention_parent parent;
TypeMention() { type_mention(this, getTypeRef(type), parent) }
diff --git a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll
index 475b6bb9b87..9aa4ffa0ab6 100644
--- a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll
+++ b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll
@@ -208,7 +208,6 @@ class VSTestAssertNonNullMethod extends AssertNonNullMethod {
/** A method that forwards to another assertion method. */
class ForwarderAssertMethod extends AssertMethod {
Assertion a;
-
Parameter p;
ForwarderAssertMethod() {
diff --git a/csharp/ql/src/semmle/code/csharp/commons/Diagnostics.qll b/csharp/ql/src/semmle/code/csharp/commons/Diagnostics.qll
index 221b13624db..edbc31b5292 100644
--- a/csharp/ql/src/semmle/code/csharp/commons/Diagnostics.qll
+++ b/csharp/ql/src/semmle/code/csharp/commons/Diagnostics.qll
@@ -9,13 +9,9 @@ class Diagnostic extends @diagnostic {
Compilation getCompilation() { diagnostic_for(this, result, _, _) }
int severity;
-
string tag;
-
string message;
-
string fullMessage;
-
Location location;
Diagnostic() { diagnostics(this, severity, tag, message, fullMessage, location) }
@@ -67,15 +63,10 @@ class CompilerError extends Diagnostic {
/** A message from an extractor. */
class ExtractorMessage extends @extractor_message {
int severity;
-
string origin;
-
string text;
-
string element;
-
string stackTrace;
-
Location location;
ExtractorMessage() {
diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll
index a3508c8d307..d2e2879fc99 100644
--- a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll
+++ b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll
@@ -338,6 +338,7 @@ private module Internal {
predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
idominance(exitBB/1, predBB/2)(_, dom, bb)
}
+
private import Internal
/**
diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll
index 628947c1b5e..85e5fa27cb7 100644
--- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll
+++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll
@@ -282,7 +282,6 @@ module ControlFlow {
*/
class ElementNode extends Node, TElementNode {
private Splits splits;
-
private ControlFlowElement cfe;
ElementNode() { this = TElementNode(cfe, splits) }
@@ -1891,6 +1890,7 @@ module ControlFlow {
)
}
}
+
import Successor
cached
@@ -1954,6 +1954,7 @@ module ControlFlow {
cached
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { result = last(cfe, _) }
}
+
import Cached
/** A control flow element that is split into multiple control flow nodes. */
@@ -1961,5 +1962,6 @@ module ControlFlow {
SplitControlFlowElement() { strictcount(this.getAControlFlowNode()) > 1 }
}
}
+
private import Internal
}
diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll
index 4b6afbeaf18..cb1af75ddfd 100644
--- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll
+++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll
@@ -194,6 +194,7 @@ module AbstractValues {
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
}
}
+
private import AbstractValues
/**
@@ -480,9 +481,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod
*/
class GuardedExpr extends AccessOrCallExpr {
private Guard g;
-
private AccessOrCallExpr sub0;
-
private AbstractValue v0;
GuardedExpr() { isGuardedByExpr(this, g, sub0, v0) }
@@ -545,9 +544,7 @@ class GuardedExpr extends AccessOrCallExpr {
*/
class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
private Guard g;
-
private AccessOrCallExpr sub0;
-
private AbstractValue v0;
GuardedControlFlowNode() { g.controlsNode(this, sub0, v0) }
@@ -597,9 +594,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
*/
class GuardedDataFlowNode extends DataFlow::ExprNode {
private Guard g;
-
private AccessOrCallExpr sub0;
-
private AbstractValue v0;
GuardedDataFlowNode() {
@@ -1455,8 +1450,10 @@ module Internal {
).getARead()
}
}
+
import CachedWithCFG
}
+
import PreCFG
/**
@@ -1576,6 +1573,7 @@ module Internal {
)
}
}
+
import Cached
/**
@@ -1612,4 +1610,5 @@ module Internal {
)
}
}
+
private import Internal
diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll
index 177cb03a9c9..0fea41321d4 100644
--- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll
+++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll
@@ -659,7 +659,6 @@ class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion {
*/
class NestedCompletion extends Completion, TNestedCompletion {
private NormalCompletion inner;
-
private Completion outer;
NestedCompletion() { this = TNestedCompletion(inner, outer) }
diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll
index 7b752ea747e..c937fc92fed 100644
--- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll
+++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll
@@ -74,6 +74,7 @@ private module Cached {
)
}
}
+
private import Cached
/**
@@ -902,7 +903,6 @@ module BooleanSplitting {
*/
class BooleanSplitImpl extends SplitImpl, TBooleanSplit {
private BooleanSplitSubKind kind;
-
private boolean branch;
BooleanSplitImpl() { this = TBooleanSplit(kind, branch) }
@@ -1393,6 +1393,7 @@ private module SuccSplits {
case2(pred, predSplits, succ, succSplits, c)
}
}
+
import SuccSplits
/** Provides logic for calculating reachable control flow nodes. */
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll
index b7ee3403ff8..c36bcc0dc8a 100755
--- a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll
@@ -66,7 +66,6 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel
/** An argument of a delegate call. */
class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateCallContext {
DelegateCall dc;
-
int arg;
DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) }
@@ -93,7 +92,6 @@ class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateC
class DelegateArgumentToLibraryCallableArgumentContext extends ArgumentCallContext,
TDelegateToLibraryCallableArgCallContext {
Expr delegate;
-
int arg;
DelegateArgumentToLibraryCallableArgumentContext() {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
index fdf73c8c5bd..6d9bab44f46 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll
@@ -111,6 +111,7 @@ private module Cached {
)
}
}
+
import Cached
/** An unbound callable. */
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll
index 8d279df6afd..9c7db07e149 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll
@@ -345,11 +345,8 @@ abstract class PathNode extends TPathNode {
private class SourcePathNode extends PathNode, TSourcePathNode {
private Ssa::Definition def;
-
private string msg;
-
private Element reason;
-
private boolean isNullArgument;
SourcePathNode() { this = TSourcePathNode(def, msg, reason, isNullArgument) }
@@ -385,7 +382,6 @@ private class SourcePathNode extends PathNode, TSourcePathNode {
private class InternalPathNode extends PathNode, TInternalPathNode {
private Ssa::Definition def;
-
private BasicBlock bb;
InternalPathNode() { this = TInternalPathNode(def, bb) }
@@ -405,11 +401,8 @@ private class InternalPathNode extends PathNode, TInternalPathNode {
private class SinkPathNode extends PathNode, TSinkPathNode {
private Ssa::Definition def;
-
private BasicBlock bb;
-
private int i;
-
private Dereference d;
SinkPathNode() { this = TSinkPathNode(def, bb, i, d) }
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll
index d63dee77a84..a4a5bfed774 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll
@@ -76,6 +76,7 @@ module Ssa {
)
}
}
+
import Cached
/**
@@ -359,6 +360,7 @@ module Ssa {
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk, rk))
}
}
+
private import SourceVariableImpl
/**
@@ -490,6 +492,7 @@ module Ssa {
override string toString() { result = getQualifier() + "." + getAssignable() }
}
}
+
private import SourceVariables
private module TrackedVariablesImpl {
@@ -536,6 +539,7 @@ module Ssa {
)
}
}
+
private import TrackedVariablesImpl
/**
@@ -874,8 +878,10 @@ module Ssa {
)
}
}
+
import Cached
}
+
private import SsaDefReaches
/**
@@ -1339,6 +1345,7 @@ module Ssa {
)
}
}
+
private import FieldOrPropsImpl
/**
@@ -1538,6 +1545,7 @@ module Ssa {
)
}
}
+
private import CapturedVariableImpl
/**
@@ -1797,6 +1805,7 @@ module Ssa {
liveAfterWriteCapturedIn(bb, i, v, _, _, _)
}
}
+
private import CapturedVariableLivenessImpl
cached
@@ -1955,6 +1964,7 @@ module Ssa {
)
}
}
+
private import SsaImpl
private string getSplitString(Definition def) {
@@ -2289,7 +2299,6 @@ module Ssa {
*/
class ExplicitDefinition extends Definition, TSsaExplicitDef {
TrackedVar tv;
-
AssignableDefinition ad;
ExplicitDefinition() { this = TSsaExplicitDef(tv, ad, _, _) }
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll
index 7ad04949c82..96f3a67bf98 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll
@@ -227,6 +227,7 @@ private module Cached {
)
}
}
+
import Cached
predicate viableCallable = viableImpl/1;
@@ -321,7 +322,6 @@ abstract class DataFlowCall extends TDataFlowCall {
/** A non-delegate C# call relevant for data flow. */
class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
private ControlFlow::Nodes::ElementNode cfn;
-
private DispatchCall dc;
NonDelegateDataFlowCall() { this = TNonDelegateCall(cfn, dc) }
@@ -352,7 +352,6 @@ abstract class DelegateDataFlowCall extends DataFlowCall {
/** An explicit delegate call relevant for data flow. */
class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelegateCall {
private ControlFlow::Nodes::ElementNode cfn;
-
private DelegateCall dc;
ExplicitDelegateDataFlowCall() { this = TExplicitDelegateCall(cfn, dc) }
@@ -379,7 +378,6 @@ class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelega
*/
class ImplicitDelegateDataFlowCall extends DelegateDataFlowCall, TImplicitDelegateCall {
private ControlFlow::Nodes::ElementNode cfn;
-
private DelegateArgumentToLibraryCallable arg;
ImplicitDelegateDataFlowCall() { this = TImplicitDelegateCall(cfn, arg) }
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
index e248fa0dae6..740f4812bdc 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
index e248fa0dae6..740f4812bdc 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
index e248fa0dae6..740f4812bdc 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
index e248fa0dae6..740f4812bdc 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
index e248fa0dae6..740f4812bdc 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll
@@ -1655,11 +1655,8 @@ module PathGraph {
*/
private class PathNodeMid extends PathNode, TPathNodeMid {
Node node;
-
CallContext cc;
-
AccessPath ap;
-
Configuration config;
PathNodeMid() { this = TPathNodeMid(node, cc, ap, config) }
@@ -1722,7 +1719,6 @@ private class PathNodeSource extends PathNodeMid {
*/
private class PathNodeSink extends PathNode, TPathNodeSink {
Node node;
-
Configuration config;
PathNodeSink() { this = TPathNodeSink(node, config) }
@@ -2190,11 +2186,8 @@ private module FlowExploration {
private class PartialPathNodePriv extends PartialPathNode {
Node node;
-
CallContext cc;
-
PartialAccessPath ap;
-
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, ap, config) }
@@ -2459,6 +2452,7 @@ private module FlowExploration {
)
}
}
+
import FlowExploration
private predicate partialFlow(
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll
index 9bb6a70c742..97052e80004 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll
@@ -363,6 +363,7 @@ private module ImplCommon {
newtype TReturnPosition =
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
}
+
import ImplCommon
pragma[noinline]
@@ -418,7 +419,6 @@ class CallContextReturn extends CallContext, TReturn {
/** A callable tagged with a relevant return kind. */
class ReturnPosition extends TReturnPosition0 {
private DataFlowCallable c;
-
private ReturnKind kind;
ReturnPosition() { this = TReturnPosition0(c, kind) }
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
index 5d120641723..7c1fdf4e033 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
@@ -269,7 +269,6 @@ module LocalFlow {
/** An argument of a C# call. */
private class Argument extends Expr {
private Expr call;
-
private int arg;
Argument() {
@@ -442,6 +441,7 @@ private module Cached {
)
}
}
+
import Cached
/** An SSA definition, viewed as a node in a data flow graph. */
@@ -589,6 +589,7 @@ private module ParameterNodes {
)
}
}
+
private import ImplicitCapturedParameterNodeImpl
/**
@@ -622,6 +623,7 @@ private module ParameterNodes {
}
}
}
+
import ParameterNodes
/** A data flow node that represents a call argument. */
@@ -753,7 +755,6 @@ private module ArgumentNodes {
*/
class ImplicitCapturedArgumentNode extends ArgumentNode, TImplicitCapturedArgumentNode {
private LocalScopeVariable v;
-
private ControlFlow::Nodes::ElementNode cfn;
ImplicitCapturedArgumentNode() { this = TImplicitCapturedArgumentNode(cfn, v) }
@@ -824,6 +825,7 @@ private module ArgumentNodes {
override string toString() { result = "malloc" }
}
}
+
import ArgumentNodes
/** A data flow node that represents a value returned by a callable. */
@@ -937,6 +939,7 @@ private module ReturnNodes {
}
}
}
+
import ReturnNodes
/** A data flow node that represents the output of a call. */
@@ -1017,7 +1020,6 @@ private module OutNodes {
*/
class ImplicitDelegateOutNode extends OutNode, TImplicitDelegateOutNode {
private ControlFlow::Nodes::ElementNode cfn;
-
private ControlFlow::Nodes::ElementNode call;
ImplicitDelegateOutNode() { this = TImplicitDelegateOutNode(cfn, call) }
@@ -1045,6 +1047,7 @@ private module OutNodes {
override string toString() { result = "[output] " + cfn }
}
}
+
import OutNodes
private class FlowThroughLibraryCallableOutRefConfiguration extends ControlFlowReachabilityConfiguration {
@@ -1146,9 +1149,7 @@ private predicate hasNonlocalValue(FieldLikeRead flr) {
/** A write to a static field/property. */
private class StaticFieldLikeJumpNode extends NonLocalJumpNode, ExprNode {
FieldLike fl;
-
FieldLikeRead flr;
-
ExprNode succ;
StaticFieldLikeJumpNode() {
@@ -1300,6 +1301,7 @@ private module PostUpdateNodes {
override string toString() { result = "[post] " + cfn.toString() }
}
}
+
private import PostUpdateNodes
/** A node that performs a type cast. */
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll
index 89c2a5fa4bf..abb4a7bec37 100755
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll
@@ -103,7 +103,6 @@ library class DelegateCallExpr extends DelegateFlowSink {
/** A delegate expression that is passed as the argument to a library callable. */
library class DelegateArgumentToLibraryCallable extends Expr {
DelegateType dt;
-
Call call;
DelegateArgumentToLibraryCallable() {
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
index 4d0bc59d2a2..425724f3a22 100755
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
@@ -170,4 +170,5 @@ module Cached {
flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, false)
}
}
+
import Cached
diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll
index dc658b43471..15420c7fcaf 100644
--- a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll
+++ b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll
@@ -91,6 +91,7 @@ private module Internal {
result = dc.(DispatchCallImpl).getADynamicTarget()
}
}
+
import Cached
/**
@@ -384,6 +385,7 @@ private module Internal {
)
}
}
+
private import SimpleTypeDataFlow
/**
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll
index e7b21f0f6ec..650c15f189a 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll
@@ -76,7 +76,6 @@ DefaultEdge defaultEdge() { result = TDefaultEdge() }
*/
class CaseEdge extends EdgeKind, TCaseEdge {
string minValue;
-
string maxValue;
CaseEdge() { this = TCaseEdge(minValue, maxValue) }
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll
index 2c1b43672fc..a7ca4593ac4 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll
@@ -59,7 +59,6 @@ abstract class IRVariable extends TIRVariable {
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var;
-
Language::Type type;
IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -110,9 +109,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
-
TempVariableTag tag;
-
Language::Type type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll
index ea0a3f72998..43f9663d2cd 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll
@@ -922,7 +922,6 @@ class ConvertInstruction extends UnaryInstruction {
*/
class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class baseClass;
-
Language::Class derivedClass;
InheritanceConversionInstruction() {
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 fda04820848..1ced8ef3282 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
@@ -196,9 +196,7 @@ class MemoryOperand extends Operand {
*/
class NonPhiOperand extends Operand {
Instruction useInstr;
-
Instruction defInstr;
-
OperandTag tag;
NonPhiOperand() {
@@ -231,7 +229,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
override MemoryOperandTag tag;
-
Overlap overlap;
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
@@ -359,7 +356,6 @@ class ThisArgumentOperand extends ArgumentOperand {
*/
class PositionalArgumentOperand extends ArgumentOperand {
override PositionalArgumentOperandTag tag;
-
int argIndex;
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
@@ -413,11 +409,8 @@ class SideEffectOperand extends TypedOperand {
*/
class PhiInputOperand extends MemoryOperand, TPhiOperand {
PhiInstruction useInstr;
-
Instruction defInstr;
-
IRBlock predecessorBlock;
-
Overlap overlap;
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll
index ccd5b8f8a0c..4ab9f89a42b 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll
@@ -16,6 +16,7 @@ TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
}
InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) }
+
import Cached
cached
@@ -304,6 +305,7 @@ private module Cached {
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() }
}
+
import CachedForDebugging
cached
diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll
index 823103b069f..bc2d7ba152f 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll
@@ -29,7 +29,6 @@ class BuiltInOperation extends TBuiltInOperation {
class ClassDerivation extends MkClassDerivation {
Class baseClass;
-
Class derivedClass;
ClassDerivation() { this = MkClassDerivation(baseClass, derivedClass) }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll
index c83e5b9b2cf..f36f90d7063 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/HardcodedCredentials.qll
@@ -166,9 +166,7 @@ module HardcodedCredentials {
*/
class HardcodedCredentialsSinkExpr extends Sink {
private string description;
-
private Element supplementaryElement;
-
private string sinkName;
HardcodedCredentialsSinkExpr() {
diff --git a/docs/language/README.rst b/docs/language/README.rst
index ac6edf8d5e5..c2fe8019908 100644
--- a/docs/language/README.rst
+++ b/docs/language/README.rst
@@ -48,9 +48,12 @@ For more information, see
Building and previewing the QL language documentation
*****************************************************
-To build and preview the QL documentation locally, you need to install Sphinx.
+To build and preview the QL documentation and QL training presentations locally, you need to
+install Sphinx 1.7.9. More recent versions of Sphinx do not work with hieroglyph,
+the Sphinx extension that we use to generate HTML slides, as explained below.
For installation options, see https://github.com/sphinx-doc/sphinx.
+
Using ``sphinx-build``
----------------------
diff --git a/docs/language/global-sphinx-files/_templates/layout.html b/docs/language/global-sphinx-files/_templates/layout.html
index e9bba0343e5..d5a714aa5e1 100644
--- a/docs/language/global-sphinx-files/_templates/layout.html
+++ b/docs/language/global-sphinx-files/_templates/layout.html
@@ -60,7 +60,7 @@
Learn QL
- QL training
+ QL for variant analysisQL toolsQueriesReference
diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst
index a190673048f..108dab99683 100644
--- a/docs/language/learn-ql/index.rst
+++ b/docs/language/learn-ql/index.rst
@@ -10,6 +10,8 @@ QL queries are easy to write and share–visit the topics below and `our open so
You can also try out QL in the `query console `__ on `LGTM.com `__.
Here, you can write QL code to query open source projects directly, without having to download snapshots and libraries.
+.. _getting-started:
+
Getting started
***************
@@ -22,6 +24,18 @@ If you are new to QL, start by looking at the following topics:
about-ql
beginner/ql-tutorials
+QL training and variant analysis examples
+******************************************
+
+To start learning how to use QL in variant analysis for a specific language, see:
+
+.. toctree::
+ :maxdepth: -1
+
+ ql-training
+
+.. _writing-ql-queries:
+
Writing QL queries
******************
diff --git a/docs/language/learn-ql/ql-training.rst b/docs/language/learn-ql/ql-training.rst
new file mode 100644
index 00000000000..1bbaa20376a
--- /dev/null
+++ b/docs/language/learn-ql/ql-training.rst
@@ -0,0 +1,63 @@
+QL training and variant analysis examples
+#########################################
+
+QL and variant analysis
+=======================
+
+`Variant analysis `__ is the process of using a known vulnerability as a seed to find similar problems in your code. Security engineers typically perform variant analysis to identify possible vulnerabilities and to ensure that these threats are properly fixed across multiple code bases.
+
+`QL `__ is Semmle's variant analysis engine, and it is also the technology that underpins LGTM, Semmle's community driven security analysis platform. Together, QL and LGTM provide continuous monitoring and scalable variant analysis for your projects, even if you don’t have your own team of dedicated security engineers. You can read more about using QL and LGTM in variant analysis in the `Semmle blog `__.
+
+The QL language is easy to learn, and exploring code using QL is the most efficient way to perform variant analysis.
+
+Learning QL for variant analysis
+================================
+
+Start learning how to use QL in variant analysis for a specific language by looking at the topics below. Each topic links to a short presentation on the QL language, QL libraries, or an example variant discovered using QL.
+
+.. |arrow-l| unicode:: U+2190
+
+.. |arrow-r| unicode:: U+2192
+
+When you have selected a presentation, use |arrow-r| and |arrow-l| to navigate between slides, press **p** to view the additional notes for a slide (where available), and press **f** to enter full-screen mode.
+
+The presentations contain a number of QL query examples.
+We recommend that you download `QL for Eclipse `__ and import the example snapshot for each presentation so that you can find the bugs mentioned in the slides.
+
+
+.. pull-quote::
+
+ Information
+
+ The presentations listed below are used in QL language and variant analysis training sessions run by Semmle engineers.
+ Therefore, be aware that the slides are designed to be presented by an instructor.
+ If you are using the slides without an instructor, please use the additional notes to help guide you through the examples.
+
+QL and variant analysis for C/C++
+---------------------------------
+
+- `Introduction to variant analysis: QL for C/C++ <../ql-training/cpp/intro-ql-cpp.html>`__–an introduction to variant analysis and QL for C/C++ programmers.
+- `Example: Bad overflow guard <../ql-training/cpp/bad-overflow-guard.html>`__–an example of iterative query development to find bad overflow guards in a C++ project.
+- `Program representation: QL for C/C++ <../ql-training/cpp/program-representation-cpp.html>`__–information on how QL analysis represents C/C++ programs.
+- `Introduction to local data flow <../ql-training/cpp/data-flow-cpp.html>`__–an introduction to analyzing local data flow in C/C++ using QL, including an example demonstrating how to develop a query to find a real CVE.
+- `Exercise: snprintf overflow <../ql-training/cpp/snprintf.html>`__–an example demonstrating how to develop a data flow query.
+- `Introduction to global data flow <../ql-training/cpp/global-data-flow-cpp.html>`__–an introduction to analyzing global data flow in C/C++ using QL.
+- `Analyzing control flow: QL for C/C++ <../ql-training/cpp/control-flow-cpp.html>`__–an introduction to analyzing control flow in C/C++ using QL.
+
+QL and variant analysis for Java
+--------------------------------
+
+- `Introduction to variant analysis: QL for Java <../ql-training/java/intro-ql-java.html>`__–an introduction to variant analysis and QL for Java programmers.
+- `Example: Query injection <../ql-training/java/query-injection-java.html>`__–an example of iterative query development to find unsanitized SPARQL injections in a Java project.
+- `Program representation: QL for Java <../ql-training/java/program-representation-java.html>`__–information on how QL analysis represents Java programs.
+- `Introduction to local data flow <../ql-training/java/data-flow-java.html>`__–an introduction to analyzing local data flow in Java using QL, including an example demonstrating how to develop a query to find a real CVE.
+- `Exercise: Apache Struts <../ql-training/java/apache-struts-java.html>`__–an example demonstrating how to develop a data flow query.
+- `Introduction to global data flow <../ql-training/java/global-data-flow-java.html>`__–an introduction to analyzing global data flow in Java using QL.
+
+More resources
+--------------
+
+- If you are completely new to QL, look at our introductory topics in :ref:`Getting started `.
+- To find more detailed information about how to write QL queries for specific languages, visit the links in :ref:`Writing QL queries `.
+- To read more about how QL queries have been used in Semmle's security research, and to read about new QL developments, visit the `Semmle blog `__.
+- Find more examples of queries written by Semmle's own security researchers in the `Semmle Demos repository `__ on GitHub.
diff --git a/docs/language/learn-ql/writing-queries/writing-queries.rst b/docs/language/learn-ql/writing-queries/writing-queries.rst
index c75361cf4bc..1c3877e1a77 100644
--- a/docs/language/learn-ql/writing-queries/writing-queries.rst
+++ b/docs/language/learn-ql/writing-queries/writing-queries.rst
@@ -27,14 +27,6 @@ Visit `Learning QL `__ to find basic infor
- :doc:`Locations and strings for QL entities <../locations>`–further detail on providing location information in query results.
- `QL style guide on GitHub `__–a guide to formatting QL for consistency and clarity.
-QL for variant analysis
-***********************
-
-Exploring code using QL is the most efficient way to perform `variant analysis `__.
-There is QL training material available to help you learn QL for variant analysis. Get started by visiting `QL training `__.
-For more information on performing variant analysis with QL, see `the Semmle blog `__ .
-
-
Viewing the built-in QL queries
*******************************
diff --git a/docs/language/ql-training-rst/_static-training/setup-slide.svg b/docs/language/ql-training-rst/_static-training/setup-slide.svg
deleted file mode 100644
index c3483a7af21..00000000000
--- a/docs/language/ql-training-rst/_static-training/setup-slide.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst b/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst
deleted file mode 100644
index 330d56830aa..00000000000
--- a/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst
+++ /dev/null
@@ -1,337 +0,0 @@
-================================
-Introduction to global data flow
-================================
-
-QL for C/C++
-
-.. container:: semmle-logo
-
- Semmle :sup:`TM`
-
-.. rst-class:: setup
-
-Setup
-=====
-
-For this example you should download:
-
-- `QL for Eclipse `__
-- `dotnet/coreclr snapshot `__
-
-.. note::
-
- For the examples in this presentation, we will be analyzing `dotnet/coreclr `__.
-
- You can query the project in `the query console `__ on LGTM.com.
-
- Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base.
-
-.. rst-class:: agenda
-
-Agenda
-======
-
-- Global taint tracking
-- Sanitizers
-- Path queries
-- Data flow models
-
-Information flow
-================
-
-- Many security problems can be phrased as an information flow problem:
-
- Given a (problem-specific) set of sources and sinks, is there a path in the data flow graph from some source to some sink?
-
-- Some examples:
-
- - SQL injection: sources are user-input, sinks are SQL queries
- - Reflected XSS: sources are HTTP requests, sinks are HTTP responses
-
-- We can solve such problems using the data flow and taint tracking libraries.
-
-Global data flow and taint tracking
-===================================
-
-- Recap:
-
- - Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot
- - Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot
-
-- For global data flow (and taint tracking), we must therefore provide restrictions to ensure the problem is tractable.
-- Typically, this involves specifying the *source* and *sink*.
-
-.. note::
-
- As we mentioned in the previous slide deck, while local data flow is feasible to compute for all functions in a snapshot, global data flow is not. This is because the number of paths becomes exponentially larger for global data flow.
-
- The global data flow (and taint tracking) avoids this problem by requiring that the query author specifies which ``sources`` and ``sinks`` are applicable. This allows the implementation to compute paths between the restricted set of nodes, rather than the full graph.
-
-Global taint tracking library
-=============================
-
-The ``semmle.code.cpp.dataflow.TaintTracking`` library provides a framework for implementing solvers for global taint tracking problems:
-
- #. Subclass ``TaintTracking::Configuration`` following this template:
-
- .. code-block:: ql
-
- class Config extends TaintTracking::Configuration {
- Config() { this = "" }
- override predicate isSource(DataFlow::Node nd) { ... }
- override predicate isSink(DataFlow::Node nd) { ... }
- }
-
- #. Use ``Config.hasFlow(source, sink)`` to find inter-procedural paths.
-
-.. note::
-
- In addition to the taint tracking configuration described here, there is also an equivalent *data flow* configuration in ``semmle.code.cpp.dataflow.DataFlow``, ``DataFlow::Configuration``. Data flow configurations are used to track whether the exact value produced by a source is used by a sink, whereas taint tracking configurations are used to determine whether the source may influence the value used at the sink. Whether you use taint tracking or data flow depends on the analysis problem you are trying to solve.
-
-Finding tainted format strings (outline)
-========================================
-
-.. literalinclude:: ../query-examples/cpp/global-data-flow-cpp-1.ql
- :language: ql
-
-.. note::
-
- Here’s the outline for a inter-procedural (that is, “global”) version of the tainted formatting strings query we saw in the previous slide deck. The same template will be applicable for most taint tracking problems.
-
-Defining sources
-================
-
-The library class ``SecurityOptions`` provides a (configurable) model of what counts as user-controlled data:
-
-.. code-block:: ql
-
- import semmle.code.cpp.security.Security
-
- class TaintedFormatConfig extends TaintTracking::Configuration {
- override predicate isSource(DataFlow::Node source) {
- exists (SecurityOptions opts |
- opts.isUserInput(source.asExpr(), _)
- )
- }
- ...
- }
-
-.. note::
-
- We first define what it means to be a *source* of tainted data for this particular problem. In this case, what we care about is whether the format string can be provided by an external user to our application or service. As there are many such ways external data could be introduced into the system, the standard QL libraries for C/C++ include an extensible API for modeling user input. In this case, we will simply use the predefined set of *user inputs*, which includes arguments provided to command line applications.
-
-
-Defining sinks (exercise)
-=========================
-
-Use the ``FormattingFunction`` class to fill in the definition of ``isSink``.
-
-.. code-block:: ql
-
- import semmle.code.cpp.security.Security
-
- class TaintedFormatConfig extends TaintTracking::Configuration {
- override predicate isSink(DataFlow::Node sink) {
- /* Fill me in */
- }
- ...
- }
-
-.. note::
-
- The second part is to define what it means to be a sink for this particular problem. The queries from the previous slide deck will be useful for this exercise.
-
-Defining sinks (answer)
-=======================
-
-Use the ``FormattingFunction`` class, we can write the sink as:
-
-.. code-block:: ql
-
- import semmle.code.cpp.security.Security
-
- class TaintedFormatConfig extends TaintTracking::Configuration {
- override predicate isSink(DataFlow::Node sink) {
- exists (FormattingFunction ff, Call c |
- c.getTarget() = ff and
- c.getArgument(ff.getFormatParameterIndex()) = sink.asExpr()
- )
- }
- ...
- }
-
-.. note::
-
- When we run this query, we should find a single result. However, it is tricky to determine whether this result is a true positive (a “real” result) because our query only reports the source and the sink, and not the path through the graph between the two.
-
-Path queries
-============
-
-Path queries provide information about the identified paths from sources to sinks. Paths can be examined in Path Explorer view.
-
-Use this template:
-
-.. code-block:: ql
-
- /**
- * ...
- * @kind path-problem
- */
-
- import semmle.code.cpp.dataflow.TaintTracking
- import DataFlow::PathGraph
- ...
- from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
- where cfg.hasFlowPath(source, sink)
- select sink, source, sink, ""
-
-.. note::
-
- To see the paths between the source and the sinks, we can convert the query to a path problem query. There are a few minor changes that need to be made for this to work–we need an additional import, to specify ``PathNode`` rather than ``Node``, and to add the source/sink to the query output (so that we can automatically determine the paths).
-
-Defining additional taint steps
-===============================
-
-Add an additional taint step that (heuristically) taints a local variable if it is a pointer, and it is passed to a function in a parameter position that taints it.
-
-.. code-block:: ql
-
- class TaintedFormatConfig extends TaintTracking::Configuration {
- override predicate isAdditionalTaintStep(DataFlow::Node pred,
- DataFlow::Node succ) {
- exists (Call c, Expr arg, LocalVariable lv |
- arg = c.getAnArgument() and
- arg = pred.asExpr() and
- arg.getFullyConverted().getUnderlyingType() instanceof PointerType and
- arg = lv.getAnAccess() and
- succ.asUninitialized() = lv
- )
- }
- ...
- }
-
-Defining sanitizers
-===================
-
-Add a sanitizer, stopping propagation at parameters of formatting functions, to avoid double-reporting:
-
-.. code-block:: ql
-
- class TaintedFormatConfig extends TaintTracking::Configuration {
- override predicate isSanitizer(DataFlow::Node nd) {
- exists (FormattingFunction ff, int idx |
- idx = ff.getFormatParameterIndex() and
- nd = DataFlow::parameterNode(ff.getParameter(idx))
- )
- }
- ...
- }
-
-Data flow models
-================
-
-- To provide models of data/taint flow through library functions, you can implement subclasses of ``DataFlowFunction`` (from ``semmle.code.cpp.models.interfaces.DataFlow``) and ``TaintFunction`` (from ``semmle.code.cpp.models.interfaces.Taint``), respectively
-
-- Example: model of taint flow from third to first parameter of ``memcpy``
-
- .. code-block:: ql
-
- class MemcpyFunction extends TaintFunction {
- MemcpyFunction() { this.hasName("memcpy") }
- override predicate hasTaintFlow(FunctionInput i, FunctionOutput o)
- i.isInParameter(2) and o.isOutParameterPointer(0)
- }
- }
-
-.. note::
-
- See the API documentation for more details about ``FunctionInput`` and ``FunctionOutput``.
-
-.. rst-class:: end-slide
-
-Extra slides
-============
-
-Exercise: How not to do global data flow
-========================================
-
-Implement a ``flowStep`` predicate extending ``localFlowStep`` with steps through function calls and returns. Why might we not want to use this?
-
-.. code-block:: ql
-
- predicate stepIn(Call c, DataFlow::Node arg, DataFlow::ParameterNode parm) {
- exists(int i | arg.asExpr() = c.getArgument(i) |
- parm.asParameter() = c.getTarget().getParameter(i))
- }
-
- predicate stepOut(Call c, DataFlow::Node ret, DataFlow::Node res) {
- exists(ReturnStmt retStmt | retStmt.getEnclosingFunction() = c.getTarget() |
- ret.asExpr() = retStmt.getExpr() and res.asExpr() = c)
- }
-
- predicate flowStep(DataFlow::Node pred, DataFlow::Node succ) {
- DataFlow::localFlowStep(pred, succ) or
- stepIn(_, pred, succ) or
- stepOut(_, pred, succ)
- }
-
-Mismatched calls and returns
-============================
-
-.. container:: column-left
-
- .. code-block:: ql
-
- char *logFormat(char *fmt) {
- log("Observed format string %s.", fmt);
- return fmt;
- }
-
- ...
- char *dangerousFmt = unvalidatedUserData();
- printf(logFormat(dangerousFmt), args);
- ...
- char *safeFmt = "Hello %s!";
- printf(logFormat(safeFmt), name);
-
-.. container:: column-right
-
- Infeasible path due to mismatched call/return pair!
-
-Balancing calls and returns
-===========================
-
-- If we simply take ``flowStep*``, we might mismatch calls and returns, causing imprecision, which in turn may cause false positives.
-
-- Instead, make sure that matching ``stepIn``/``stepOut`` pairs talk about the same call site:
-
- .. code-block:: ql
-
- predicate balancedPath(DataFlow::Node src, DataFlow::Node snk) {
- src = snk or DataFlow::localFlowStep(src, snk) or
- exists(DataFlow::Node m | balancedPath(src, m) | balancedPath(m, snk)) or
- exists(Call c, DataFlow::Node parm, DataFlow::Node ret |
- stepIn(c, src, parm) and
- balancedPath(parm, ret) and
- stepOut(c, ret, snk)
- )
- }
-
-Summary-based global data flow
-==============================
-
-- To avoid traversing the same paths many times, we compute *function summaries* that record if a function parameter flows into a return value:
-
- .. code-block:: ql
-
- predicate returnsParameter(Function f, int i) {
- exists (Parameter p, ReturnStmt retStmt, Expr ret |
- p = f.getParameter(i) and
- retStmt.getEnclosingFunction() = f and
- ret = retStmt.getExpr() and
- balancedPath(DataFlow::parameterNode(p), DataFlow::exprNode(ret))
- )
- }
-
-- Use this predicate in balancedPath instead of ``stepIn``/``stepOut`` pairs.
-
diff --git a/docs/language/ql-training-rst/cpp/program-representation-cpp.rst b/docs/language/ql-training-rst/cpp/program-representation-cpp.rst
deleted file mode 100644
index 95ea3bbc4df..00000000000
--- a/docs/language/ql-training-rst/cpp/program-representation-cpp.rst
+++ /dev/null
@@ -1,189 +0,0 @@
-======================
-Program representation
-======================
-
-QL for C/C++
-
-.. container:: semmle-logo
-
- Semmle :sup:`TM`
-
-.. rst-class:: agenda
-
-Agenda
-======
-
-- Abstract syntax trees
-- Database representation
-- Symbol tables
-- Variables
-- Functions
-
-Abstract syntax trees
-=====================
-
-The basic representation of an analyzed program is an *abstract syntax tree (AST)*.
-
-.. container:: column-left
-
- .. code-block:: cpp
-
- try {
- ...
- } catch (AnException e) {
- }
-
-.. container:: ast-graph
-
- .. graphviz::
-
- digraph {
- graph [ dpi = 1000 ]
- node [shape=polygon,sides=4,color=blue4,style="filled,rounded", fontname=consolas,fontcolor=white]
- a [label=]
- b [label=]
- c [label=<...>,color=white,fontcolor=black]
- d [label=]
- e [label=<...>,color=white,fontcolor=black]
- f [label=<...>,color=white,fontcolor=black]
- g [label=<...>,color=white,fontcolor=black]
-
- a -> {b, c}
- b -> {d, e}
- d -> {f, g}
- }
-
-
-
-.. note::
-
- When writing queries in QL it is important to have in mind the underlying representation of the program which is stored in the database. Typically queries make use of the “AST” representation of the program–a tree structure where program elements are nested within other program elements.
-
- The “Introducing the C/C++ libraries” help topic contains a more complete overview of important AST classes and the rest of the C++ QL libraries: https://help.semmle.com/QL/learn-ql/ql/cpp/introduce-libraries-cpp.html
-
-Database representations of ASTs
-================================
-
-AST nodes and other program elements are encoded in the database as *entity values*. Entities are implemented as integers, but in QL they are opaque–all one can do with them is to check their equality.
-
-Each entity belongs to an entity type. Entity types have names starting with “@” and are defined in the database schema (not in QL).
-
-Properties of AST nodes and their relationships to each other are encoded by database relations, which are predicates defined in the database (not in QL).
-
-Entity types are rarely used directly, the usual pattern is to define a QL class that extends the type and exposes properties of its entities through member predicates.
-
-.. note::
-
- ASTs are a typical example of the kind of data representation one finds in object-oriented programming, with data-carrying nodes that reference each other. At first glance, QL, which can only work with atomic values, does not seem to be well suited for working with this kind of data. However, ultimately all that we require of the nodes in an AST is that they have an identity. The relationships among nodes, usually implemented by reference-valued object fields in other languages, can just as well (and arguably more naturally) be represented as relations over nodes. Attaching data (such as strings or numbers) to nodes can also be represented with relations over nodes and primitive values. All we need is a way for relations to reference nodes. This is achieved in QL (as in other database languages) by means of *entity values* (or entities, for short), which are opaque atomic values, implemented as integers under the hood.
-
- It is the job of the extractor to create entity values for all AST nodes and populate database relations that encode the relationship between AST nodes and any values associated with them. These relations are *extensional*, that is, explicitly stored in the database, unlike the relations described by QL predicates, which we also refer to as *intensional* relations. Entity values belong to *entity types*, whose name starts with “@” to set them apart from primitive types and classes.
-
- The interface between entity types and extensional relations on the one hand and QL predicates and classes on the other hand is provided by the *database schema*, which defines the available entity types and the schema of each extensional relation, that is, how many columns the relation has, and which entity type or primitive type the values in each column come from. QL programs can refer to entity types and extensional relations just as they would refer to QL classes and predicates, with the restriction that entity types cannot be directly selected in a “select” clause, since they do not have a well-defined string representation.
-
- For example, the database schema for C++ snapshot databases is here: https://github.com/Semmle/ql/blob/master/cpp/ql/src/semmlecode.cpp.dbscheme
-
-AST QL classes
-==============
-
-Important AST classes include:
-
-- ``Expr``: expressions such as assignments, variable references, function calls, ...
-- ``Stmt``: statements such as conditionals, loops, try statements, ...
-- ``DeclarationEntry``: places where functions, variables or types are declared and/or defined
-
-These three (and all other AST classes) are subclasses of ``Element``.
-
-.. note::
-
- The “Introducing the C/C++ libraries” help topic contains a more complete overview of important AST classes and the rest of the C++ QL libraries: https://help.semmle.com/QL/learn-ql/ql/cpp/introduce-libraries-cpp.html
-
-Symbol table
-============
-
-The database also includes information about the symbol table associated with a program:
-
-- ``Variable``: all variables, including local variables, global variables, static variables and member variables
-
-- ``Function``: all functions, including member function
-
-- ``Type``: built-in and user-defined types
-
-.. note::
-
- The “Introducing the C/C++ libraries” help topic contains a more complete overview of important symbol table classes and the rest of the C++ QL libraries: https://help.semmle.com/QL/learn-ql/ql/cpp/introduce-libraries-cpp.html
-
-Working with variables
-======================
-
-``Variable`` represents program variables, including locally scoped variables (``LocalScopeVariable``), global variables (``GlobalVariable``), and others:
-
-- ``string Variable.getName()``
-- ``Type Variable.getType()``
-
-``Access`` represents references to declared entities such as functions (``FunctionAccess``) and variables (``VariableAccess``), including fields (``FieldAccess``).
-
-- ``Declaration Access.getTarget()``
-
-``VariableDeclarationEntry`` represents declarations or definitions of a variable.
-
-- ``Variable VariableDeclarationEntry.getVariable()``
-
-Working with functions
-======================
-
-Functions are represented by the Function QL class. Each declaration or definition of a function is represented by a ``FunctionDeclarationEntry``.
-
-Calls to functions are modeled by QL class Call and its subclasses:
-
-- ``Call.getTarget()`` gets the declared target of the call; undefined for calls through function pointers
-- ``Function.getACallToThisFunction()`` gets a call to this function
-
-Typically, functions are identified by name:
-
-- ``string Function.getName()``
-- ``string Function.getQualifiedName()``
-
-Working with preprocessor logic
-===============================
-
-Macros and other preprocessor directives can easily cause confusion when analyzing programs:
-
-- AST structure reflects the program *after* preprocessing.
-- Locations refer to the original source text *before* preprocessing.
-
-For example, in:
-
- .. code-block:: cpp
-
- #define square(x) x*x
- y = square(y0), z = square(z0)
-
-there are no AST nodes corresponding to ``square(y0)`` or ``square(z0)``, but there are AST nodes corresponding to ``y0*y0`` and ``z0*z0``.
-
-.. note::
-
- The C preprocessor poses a dilemma: un-preprocessed code cannot, in general, be parsed and analyzed meaningfully, but showing results in preprocessed code is not useful to developers. Our solution is to base the AST representation on preprocessed source (in the same way as compilers do), but associate AST nodes with locations in the original source text.
-
-Working with macros
-===================
-
- .. code-block:: cpp
-
- #define square(x) x*x
- y = square(y0), z = square(z0)
-
-is represented in the snapshot database as:
-
-- A Macro entity representing the text of the *head* and *body* of the macro
-- Assignment nodes, representing the two assignments after preprocessing
-
- - Left-hand sides are ``VariableAccess`` nodes of y and z
- - Right-hand sides are ``MulExpr`` nodes representing ``y0*y0`` and ``z0*z0``
-
-- A ``MacroAccess`` entity, which associates the Macro with the ``MulExprs``
-
-Useful predicates on ``Element``: ``isInMacroExpansion()``, ``isAffectedByMacro()``
-
-.. note::
-
- The snapshot also contains information about macro definitions, which are represented by class ``Macro``. These macro definitions are related to the AST nodes resulting from their uses by the class ``MacroAccess``.
\ No newline at end of file
diff --git a/docs/language/ql-training-rst/index.rst b/docs/language/ql-training-rst/index.rst
deleted file mode 100644
index a7af5b375aa..00000000000
--- a/docs/language/ql-training-rst/index.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-QL training and variant analysis examples
-=========================================
-
-.. container:: semmle-logo
-
- Semmle :sup:`TM`
-
-.. toctree::
- :glob:
- :maxdepth: 1
- :hidden:
-
- ./cpp/intro-ql-cpp
- ./cpp/bad-overflow-guard
- ./cpp/program-representation-cpp
- ./cpp/data-flow-cpp
- ./cpp/snprintf
- ./cpp/global-data-flow-cpp
- ./cpp/control-flow-cpp
-
-.. toctree::
- :glob:
- :maxdepth: 1
- :hidden:
-
- ./java/intro-ql-java
\ No newline at end of file
diff --git a/docs/language/ql-training-rst/_static-training/alternative-slide.svg b/docs/language/ql-training/_static-training/alternative-slide.svg
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/alternative-slide.svg
rename to docs/language/ql-training/_static-training/alternative-slide.svg
diff --git a/docs/language/ql-training-rst/_static-training/analysis-overview.png b/docs/language/ql-training/_static-training/analysis-overview.png
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/analysis-overview.png
rename to docs/language/ql-training/_static-training/analysis-overview.png
diff --git a/docs/language/ql-training-rst/_static-training/curiosity.png b/docs/language/ql-training/_static-training/curiosity.png
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/curiosity.png
rename to docs/language/ql-training/_static-training/curiosity.png
diff --git a/docs/language/ql-training-rst/_static-training/curiosity2.png b/docs/language/ql-training/_static-training/curiosity2.png
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/curiosity2.png
rename to docs/language/ql-training/_static-training/curiosity2.png
diff --git a/docs/language/ql-training-rst/_static-training/end-slide.svg b/docs/language/ql-training/_static-training/end-slide.svg
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/end-slide.svg
rename to docs/language/ql-training/_static-training/end-slide.svg
diff --git a/docs/language/ql-training/_static-training/java-data-flow-code-example.svg b/docs/language/ql-training/_static-training/java-data-flow-code-example.svg
new file mode 100644
index 00000000000..3a2b189c264
--- /dev/null
+++ b/docs/language/ql-training/_static-training/java-data-flow-code-example.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/language/ql-training/_static-training/java-expression-ast.svg b/docs/language/ql-training/_static-training/java-expression-ast.svg
new file mode 100644
index 00000000000..b8a89e31474
--- /dev/null
+++ b/docs/language/ql-training/_static-training/java-expression-ast.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/language/ql-training/_static-training/mismatched-calls-and-returns.svg b/docs/language/ql-training/_static-training/mismatched-calls-and-returns.svg
new file mode 100644
index 00000000000..93f9bbe1648
--- /dev/null
+++ b/docs/language/ql-training/_static-training/mismatched-calls-and-returns.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/language/ql-training-rst/_static-training/normal-slide.svg b/docs/language/ql-training/_static-training/normal-slide.svg
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/normal-slide.svg
rename to docs/language/ql-training/_static-training/normal-slide.svg
diff --git a/docs/language/ql-training/_static-training/setup-slide.svg b/docs/language/ql-training/_static-training/setup-slide.svg
new file mode 100644
index 00000000000..cc2662e61c4
--- /dev/null
+++ b/docs/language/ql-training/_static-training/setup-slide.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/language/ql-training-rst/_static-training/slides-semmle-2/end_slide.html b/docs/language/ql-training/_static-training/slides-semmle-2/end_slide.html
similarity index 100%
rename from docs/language/ql-training-rst/_static-training/slides-semmle-2/end_slide.html
rename to docs/language/ql-training/_static-training/slides-semmle-2/end_slide.html
diff --git a/docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html b/docs/language/ql-training/_static-training/slides-semmle-2/layout.html
similarity index 99%
rename from docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html
rename to docs/language/ql-training/_static-training/slides-semmle-2/layout.html
index 4c2ef333cb2..f0101ddfbc6 100644
--- a/docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html
+++ b/docs/language/ql-training/_static-training/slides-semmle-2/layout.html
@@ -134,7 +134,7 @@ URL: https://code.google.com/p/io-2012-slides
{% endblock %}
-