From 2a30898af6ebfd0b580190a7e586b2f5e6f66b10 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 12 Feb 2024 12:32:46 +0100
Subject: [PATCH 01/11] Go: Promote `go/missing-jwt-signature-check` from
experimental
---
.../ext/github.com.dgrijalva.jwt-go.model.yml | 16 +++++-
.../ext/github.com.go-jose.go-jose.model.yml | 14 +++++
.../ext/github.com.golang-jwt.jwt.model.yml | 18 +++++-
.../lib/ext/gopkg.in.square.go-jose.model.yml | 14 +++++
go/ql/lib/go.qll | 1 +
go/ql/lib/semmle/go/frameworks/GoJose.qll | 40 ++++++++++---
go/ql/lib/semmle/go/frameworks/Jwt.qll | 57 +++++++++++++++++++
.../go/security/MissingJwtSignatureCheck.qll | 40 +++++++++++++
...MissingJwtSignatureCheckCustomizations.qll | 48 ++++++++++++++++
.../CWE-347/MissingJwtSignatureCheck.qhelp | 25 ++++++++
.../CWE-347/MissingJwtSignatureCheck.ql | 21 +++++++
.../CWE-347/MissingJwtSignatureCheckBad.go | 21 +++++++
.../CWE-347/MissingJwtSignatureCheckGood.go | 22 +++++++
...6-missing-jwt-signature-check-promotion.md | 4 ++
go/ql/src/experimental/CWE-347/Example.go | 39 -------------
.../CWE-347/ParseJWTWithoutVerification.qhelp | 34 -----------
.../CWE-347/ParseJWTWithoutVerification.ql | 57 -------------------
.../CWE-347/ParseJWTWithoutVerification.qlref | 1 -
.../MissingJwtSignatureCheck.expected} | 0
.../CWE-347/MissingJwtSignatureCheck.qlref | 1 +
.../Security}/CWE-347/go-jose.v3.go | 0
.../Security}/CWE-347/go.mod | 0
.../Security}/CWE-347/golang-jwt-v5.go | 0
.../github.com/go-jose/go-jose/v3/jwt/stub.go | 0
.../github.com/golang-jwt/jwt/v5/stub.go | 0
.../Security}/CWE-347/vendor/modules.txt | 0
26 files changed, 332 insertions(+), 141 deletions(-)
create mode 100644 go/ql/lib/ext/github.com.go-jose.go-jose.model.yml
create mode 100644 go/ql/lib/ext/gopkg.in.square.go-jose.model.yml
create mode 100644 go/ql/lib/semmle/go/frameworks/Jwt.qll
create mode 100644 go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll
create mode 100644 go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll
create mode 100644 go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
create mode 100644 go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
create mode 100644 go/ql/src/Security/CWE-347/MissingJwtSignatureCheckBad.go
create mode 100644 go/ql/src/Security/CWE-347/MissingJwtSignatureCheckGood.go
create mode 100644 go/ql/src/change-notes/2024-02-06-missing-jwt-signature-check-promotion.md
delete mode 100644 go/ql/src/experimental/CWE-347/Example.go
delete mode 100644 go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.qhelp
delete mode 100644 go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.ql
delete mode 100644 go/ql/test/experimental/CWE-347/ParseJWTWithoutVerification.qlref
rename go/ql/test/{experimental/CWE-347/ParseJWTWithoutVerification.expected => query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected} (100%)
create mode 100644 go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref
rename go/ql/test/{experimental => query-tests/Security}/CWE-347/go-jose.v3.go (100%)
rename go/ql/test/{experimental => query-tests/Security}/CWE-347/go.mod (100%)
rename go/ql/test/{experimental => query-tests/Security}/CWE-347/golang-jwt-v5.go (100%)
rename go/ql/test/{experimental => query-tests/Security}/CWE-347/vendor/github.com/go-jose/go-jose/v3/jwt/stub.go (100%)
rename go/ql/test/{experimental => query-tests/Security}/CWE-347/vendor/github.com/golang-jwt/jwt/v5/stub.go (100%)
rename go/ql/test/{experimental => query-tests/Security}/CWE-347/vendor/modules.txt (100%)
diff --git a/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml b/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
index 9f03151231f..8a27cc21d19 100644
--- a/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
+++ b/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
@@ -3,5 +3,19 @@ extensions:
pack: codeql/go-all
extensible: sinkModel
data:
- - ["github.com/dgrijalva/jwt-go", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
- ["github.com/dgrijalva/jwt-go", "SigningMethod", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "Parser", True, "ParseUnverified", "", "", "Argument[0]", "jwt", "manual"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["github.com/dgrijalva/jwt-go", "", True, "Parse", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "Parser", True, "Parse", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, "ParseWithClaims", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "Parser", True, "ParseWithClaims", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, "ParseECPrivateKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, "ParseECPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, "ParseRSAPrivateKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, "ParseRSAPrivateKeyFromPEMWithPassword", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, ParseRSAPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
diff --git a/go/ql/lib/ext/github.com.go-jose.go-jose.model.yml b/go/ql/lib/ext/github.com.go-jose.go-jose.model.yml
new file mode 100644
index 00000000000..bd13c79ea3a
--- /dev/null
+++ b/go/ql/lib/ext/github.com.go-jose.go-jose.model.yml
@@ -0,0 +1,14 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/go-jose/go-jose/$ANYVERSION/jwt", "JSONWebToken", True, "UnsafeClaimsWithoutVerification", "", "", "Argument[-1]", "jwt", "manual"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["github.com/go-jose/go-jose/$ANYVERSION/jwt", "", True, "ParseEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/go-jose/go-jose/$ANYVERSION/jwt", "", True, "ParseSigned", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/go-jose/go-jose/$ANYVERSION/jwt", "NestedJSONWebToken", True, "ParseSignedAndEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/go-jose/go-jose/$ANYVERSION/jwt", "NestedJSONWebToken", True, "Decrypt", "", "", "Argument[-1]", "ReturnValue[0]", "taint", "manual"]
diff --git a/go/ql/lib/ext/github.com.golang-jwt.jwt.model.yml b/go/ql/lib/ext/github.com.golang-jwt.jwt.model.yml
index 218550ac559..3f6eaac89b6 100644
--- a/go/ql/lib/ext/github.com.golang-jwt.jwt.model.yml
+++ b/go/ql/lib/ext/github.com.golang-jwt.jwt.model.yml
@@ -3,5 +3,21 @@ extensions:
pack: codeql/go-all
extensible: sinkModel
data:
- - ["github.com/golang-jwt/jwt", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
- ["github.com/golang-jwt/jwt", "SigningMethod", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
+ - ["github.com/golang-jwt/jwt", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
+ - ["github.com/golang-jwt/jwt", "Parser", True, "ParseUnverified", "", "", "Argument[0]", "jwt", "manual"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["github.com/golang-jwt/jwt", "", True, "Parse", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "Parser", True, "Parse", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseWithClaims", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "Parser", True, "ParseWithClaims", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseECPrivateKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseECPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseEdPrivateKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseEdPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseRSAPrivateKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "ParseRSAPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/golang-jwt/jwt", "", True, "RegisterSigningMethod", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
diff --git a/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml b/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml
new file mode 100644
index 00000000000..d526ac893a7
--- /dev/null
+++ b/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml
@@ -0,0 +1,14 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "JSONWebToken", True, "UnsafeClaimsWithoutVerification", "", "", "Argument[-1]", "jwt", "manual"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "", True, "ParseEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "", True, "ParseSigned", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "NestedJSONWebToken", True, "ParseSignedAndEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "NestedJSONWebToken", True, "Decrypt", "", "", "Argument[-1]", "ReturnValue[0]", "taint", "manual"]
diff --git a/go/ql/lib/go.qll b/go/ql/lib/go.qll
index 779482a3de1..9260c988eaa 100644
--- a/go/ql/lib/go.qll
+++ b/go/ql/lib/go.qll
@@ -52,6 +52,7 @@ import semmle.go.frameworks.GoMicro
import semmle.go.frameworks.GoRestfulHttp
import semmle.go.frameworks.Gqlgen
import semmle.go.frameworks.Iris
+import semmle.go.frameworks.Jwt
import semmle.go.frameworks.K8sIoApimachineryPkgRuntime
import semmle.go.frameworks.K8sIoApiCoreV1
import semmle.go.frameworks.K8sIoClientGo
diff --git a/go/ql/lib/semmle/go/frameworks/GoJose.qll b/go/ql/lib/semmle/go/frameworks/GoJose.qll
index a0796dee328..faae97b2d9f 100644
--- a/go/ql/lib/semmle/go/frameworks/GoJose.qll
+++ b/go/ql/lib/semmle/go/frameworks/GoJose.qll
@@ -9,16 +9,40 @@ private import semmle.go.security.HardcodedCredentials
private module GoJose {
private class GoJoseKey extends HardcodedCredentials::Sink {
GoJoseKey() {
- exists(Field f, string pkg |
- pkg =
- [
- package("github.com/square/go-jose", ""), package("github.com/go-jose/go-jose", ""),
- "gopkg.in/square/go-jose.v2"
- ]
- |
- f.hasQualifiedName(pkg, ["Recipient", "SigningKey"], "Key") and
+ exists(Field f |
+ f.hasQualifiedName(goJosePackage(), ["Recipient", "SigningKey"], "Key") and
f.getAWrite().getRhs() = this
)
}
}
+
+ private string goJosePackage() {
+ result =
+ [
+ package("github.com/square/go-jose", ""), package("github.com/go-jose/go-jose", ""),
+ "gopkg.in/square/go-jose.v2"
+ ]
+ }
+
+ /**
+ * Provides classes and predicates for working with the `gopkg.in/square/go-jose/jwt` and
+ * `github.com/go-jose/go-jose/jwt` packages.
+ */
+ private module Jwt {
+ private import semmle.go.security.MissingJwtSignatureCheckCustomizations::MissingJwtSignatureCheck
+
+ /** The method `JSONWebToken.Claims`. */
+ private class GoJoseParseWithClaims extends JwtSafeParse {
+ GoJoseParseWithClaims() {
+ this.(Method).hasQualifiedName(goJoseJwtPackage(), "JSONWebToken", "Claims")
+ }
+
+ override int getTokenArgNum() { result = -1 }
+ }
+
+ /** Gets the package names `gopkg.in/square/go-jose/jwt` and `github.com/go-jose/go-jose/jwt`. */
+ private string goJoseJwtPackage() {
+ result = package(["gopkg.in/square/go-jose", "github.com/go-jose/go-jose"], "jwt")
+ }
+ }
}
diff --git a/go/ql/lib/semmle/go/frameworks/Jwt.qll b/go/ql/lib/semmle/go/frameworks/Jwt.qll
new file mode 100644
index 00000000000..681ead26834
--- /dev/null
+++ b/go/ql/lib/semmle/go/frameworks/Jwt.qll
@@ -0,0 +1,57 @@
+/**
+ * Provides classes and predicates for working with the `github.com/golang-jwt/jwt` and
+ * `github.com/dgrijalva/jwt-go` packages.
+ */
+
+import go
+private import semmle.go.security.MissingJwtSignatureCheckCustomizations::MissingJwtSignatureCheck
+
+/** The function `jwt.Parse` or the method `Parser.Parse`. */
+private class GolangJwtParse extends JwtSafeParse {
+ GolangJwtParse() {
+ this.hasQualifiedName(golangJwtPackage(), "Parse")
+ or
+ this.(Method).hasQualifiedName(golangJwtPackage(), "Parser", "Parse")
+ }
+
+ override int getTokenArgNum() { result = 0 }
+}
+
+/** The function `jwt.ParseWithClaims` or the method `Parser.ParseWithClaims`. */
+private class GolangJwtParseWithClaims extends JwtSafeParse {
+ GolangJwtParseWithClaims() {
+ this.hasQualifiedName(golangJwtPackage(), "ParseWithClaims")
+ or
+ this.(Method).hasQualifiedName(golangJwtPackage(), "Parser", "ParseWithClaims")
+ }
+
+ override int getTokenArgNum() { result = 0 }
+}
+
+/** The function `jwt.ParseFromRequest`. */
+private class GolangJwtParseFromRequest extends JwtSafeParse {
+ GolangJwtParseFromRequest() {
+ this.hasQualifiedName(golangJwtRequestPackage(), "ParseFromRequest")
+ }
+
+ override int getTokenArgNum() { result = 0 }
+}
+
+/** The function `jwt.ParseFromRequestWithClaims`. */
+private class GolangJwtParseFromRequestWithClaims extends JwtSafeParse {
+ GolangJwtParseFromRequestWithClaims() {
+ this.hasQualifiedName(golangJwtRequestPackage(), "ParseFromRequestWithClaims")
+ }
+
+ override int getTokenArgNum() { result = 0 }
+}
+
+/** Gets the pakcage names `github.com/golang-jwt/jwt` and `github.com/dgrijalva/jwt-go`. */
+private string golangJwtPackage() {
+ result = package(["github.com/golang-jwt/jwt", "github.com/dgrijalva/jwt-go"], "")
+}
+
+/** Gets the package names `github.com/golang-jwt/jwt/request` and `github.com/dgrijalva/jwt-go/request`. */
+private string golangJwtRequestPackage() {
+ result = package(["github.com/golang-jwt/jwt", "github.com/dgrijalva/jwt-go"], "request")
+}
diff --git a/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll
new file mode 100644
index 00000000000..346264900fb
--- /dev/null
+++ b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll
@@ -0,0 +1,40 @@
+/**
+ * Provides a taint tracking flow for reasoning about JWT vulnerabilities.
+ *
+ * Note: for performance reasons, only import this file if `MissingJwtSignatureCheck::Config` or `MissingJwtSignatureCheck::Flow` are needed,
+ * otherwise `MissingJwtSignatureCheckCustomizations` should be imported instead.
+ */
+
+import go
+
+/** Provides a taint-tracking flow for reasoning about JWT vulnerabilities. */
+module MissingJwtSignatureCheck {
+ import MissingJwtSignatureCheckCustomizations::MissingJwtSignatureCheck
+
+ module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) {
+ source instanceof Source and
+ not SafeParse::flow(source, _)
+ }
+
+ predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ any(AdditionalFlowStep s).step(nodeFrom, nodeTo)
+ }
+ }
+
+ module Flow = TaintTracking::Global;
+
+ private module SafeParseConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ predicate isSink(DataFlow::Node sink) { sink = any(JwtSafeParse jwtParse).getTokenArg() }
+
+ predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ any(AdditionalFlowStep s).step(nodeFrom, nodeTo)
+ }
+ }
+
+ private module SafeParse = TaintTracking::Global;
+}
diff --git a/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll
new file mode 100644
index 00000000000..bfc2a18b3b1
--- /dev/null
+++ b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll
@@ -0,0 +1,48 @@
+import go
+private import semmle.go.dataflow.ExternalFlow
+private import codeql.util.Unit
+
+module MissingJwtSignatureCheck {
+ /**
+ * A data flow source for JWT vulnerabilities.
+ */
+ abstract class Source extends DataFlow::Node { }
+
+ /**
+ * A data flow sink for JWT vulnerabilities.
+ */
+ abstract class Sink extends DataFlow::Node { }
+
+ /**
+ * A sanitizer for JWT vulnerabilities.
+ */
+ abstract class Sanitizer extends DataFlow::Node { }
+
+ /** An additional flow step for JWT vulnerabilities. */
+ class AdditionalFlowStep extends Unit {
+ /**
+ * Holds if the step from `node1` to `node2` should be considered a flow
+ * step for configurations related to JWT vulnerabilities.
+ */
+ abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
+ }
+
+ /** A function that parses and correctly validates a JWT token. */
+ abstract class JwtSafeParse extends Function {
+ /** Gets the position of the JWT argument in a call to this function. */
+ abstract int getTokenArgNum();
+
+ /** Gets the JWT argument of a call to this function. */
+ DataFlow::Node getTokenArg() {
+ this.getTokenArgNum() != -1 and result = this.getACall().getArgument(this.getTokenArgNum())
+ or
+ this.getTokenArgNum() = -1 and result = this.getACall().getReceiver()
+ }
+ }
+
+ private class DefaultSource extends Source instanceof UntrustedFlowSource { }
+
+ private class DefaultSink extends Sink {
+ DefaultSink() { sinkNode(this, "jwt") }
+ }
+}
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
new file mode 100644
index 00000000000..78643506041
--- /dev/null
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
@@ -0,0 +1,25 @@
+
+
+
+ Applications decoding a JSON Web Token (JWT) may be vulnerable when the
+ signature is not correctly verified in the process.
+
+
+ Always verify the signature by using the appropriate methods depending on the JWT library,
+ or use a library that verifies it by default.
+
+
+ The following example shows a case where a JWT is parsed without verifying the
+ signature.
+
+ In the example below, the appropriate function for parsing a JWT
+ and verifying its signature is used.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
new file mode 100644
index 00000000000..3b89201b34f
--- /dev/null
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
@@ -0,0 +1,21 @@
+/**
+ * @name Missing JWT signature check
+ * @description Failing to check the Json Web Token (JWT) signature may allow an attacker to forge their own tokens.
+ * @kind path-problem
+ * @problem.severity error
+ * @security-severity 7.8
+ * @precision high
+ * @id go/missing-jwt-signature-check
+ * @tags security
+ * external/cwe/cwe-347
+ */
+
+import go
+import semmle.go.security.MissingJwtSignatureCheck
+import MissingJwtSignatureCheck::Flow::PathGraph
+
+from MissingJwtSignatureCheck::Flow::PathNode source, MissingJwtSignatureCheck::Flow::PathNode sink
+where MissingJwtSignatureCheck::Flow::flowPath(source, sink)
+select sink.getNode(), source, sink,
+ "This JWT is parsed without verification and received from $@.", source.getNode(),
+ "this user-controlled source"
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheckBad.go b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheckBad.go
new file mode 100644
index 00000000000..4fad1c57ebe
--- /dev/null
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheckBad.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "fmt"
+ "log"
+
+ "github.com/golang-jwt/jwt/v5"
+)
+
+type User struct{}
+
+func decodeJwt(token string) {
+ // BAD: JWT is only decoded without signature verification
+ fmt.Println("only decoding JWT")
+ DecodedToken, _, err := jwt.NewParser().ParseUnverified(token, &User{})
+ if claims, ok := DecodedToken.Claims.(*User); ok {
+ fmt.Printf("DecodedToken:%v\n", claims)
+ } else {
+ log.Fatal("error", err)
+ }
+}
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheckGood.go b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheckGood.go
new file mode 100644
index 00000000000..699a20c3278
--- /dev/null
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheckGood.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "fmt"
+ "log"
+
+ "github.com/golang-jwt/jwt/v5"
+)
+
+type User struct{}
+
+func parseJwt(token string, jwtKey []byte) {
+ // GOOD: JWT is parsed with signature verification using jwtKey
+ DecodedToken, err := jwt.ParseWithClaims(token, &User{}, func(token *jwt.Token) (interface{}, error) {
+ return jwtKey, nil
+ })
+ if claims, ok := DecodedToken.Claims.(*User); ok && DecodedToken.Valid && !err {
+ fmt.Printf("DecodedToken:%v\n", claims)
+ } else {
+ log.Fatal(err)
+ }
+}
diff --git a/go/ql/src/change-notes/2024-02-06-missing-jwt-signature-check-promotion.md b/go/ql/src/change-notes/2024-02-06-missing-jwt-signature-check-promotion.md
new file mode 100644
index 00000000000..3fdb29af01e
--- /dev/null
+++ b/go/ql/src/change-notes/2024-02-06-missing-jwt-signature-check-promotion.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* The query "Missing JWT signature check" (`go/missing-jwt-signature-check`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @am0o0](https://github.com/github/codeql/pull/14075).
diff --git a/go/ql/src/experimental/CWE-347/Example.go b/go/ql/src/experimental/CWE-347/Example.go
deleted file mode 100644
index ee59d836439..00000000000
--- a/go/ql/src/experimental/CWE-347/Example.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- "fmt"
- "log"
-
- "github.com/golang-jwt/jwt/v5"
-)
-
-func main() {
- // BAD: only decode jwt without verification
- notVerifyJWT(token)
-
- // GOOD: decode with verification or verify plus decode
- notVerifyJWT(token)
- VerifyJWT(token)
-}
-
-func notVerifyJWT(signedToken string) {
- fmt.Println("only decoding JWT")
- DecodedToken, _, err := jwt.NewParser().ParseUnverified(signedToken, &CustomerInfo{})
- if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok {
- fmt.Printf("DecodedToken:%v\n", claims)
- } else {
- log.Fatal("error", err)
- }
-}
-func LoadJwtKey(token *jwt.Token) (interface{}, error) {
- return ARandomJwtKey, nil
-}
-func verifyJWT(signedToken string) {
- fmt.Println("verifying JWT")
- DecodedToken, err := jwt.ParseWithClaims(signedToken, &CustomerInfo{}, LoadJwtKey)
- if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok && DecodedToken.Valid {
- fmt.Printf("NAME:%v ,ID:%v\n", claims.Name, claims.ID)
- } else {
- log.Fatal(err)
- }
-}
diff --git a/go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.qhelp b/go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.qhelp
deleted file mode 100644
index cb1edb2f659..00000000000
--- a/go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.qhelp
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
- A JSON Web Token (JWT) is used for authenticating and managing users in an application.
-
-
- Only Decoding JWTs without checking if they have a valid signature or not can lead to security vulnerabilities.
-
-
-
-
-
-
- Don't use methods that only decode JWT, Instead use methods that verify the signature of JWT.
-
-
-
-
-
-
- In the following code you can see an Example from a popular Library.
-
-
-
-
-
-
-
- JWT audience claim is not verified
-
-
-
-
\ No newline at end of file
diff --git a/go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.ql b/go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.ql
deleted file mode 100644
index fb457c2f449..00000000000
--- a/go/ql/src/experimental/CWE-347/ParseJWTWithoutVerification.ql
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @name Use of JWT Methods that only decode user provided Token
- * @description Using JWT methods without verification can cause to authorization or authentication bypass
- * @kind path-problem
- * @problem.severity error
- * @id go/parse-jwt-without-verification
- * @tags security
- * experimental
- * external/cwe/cwe-347
- */
-
-import go
-import experimental.frameworks.JWT
-
-module WithValidationConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
-
- predicate isSink(DataFlow::Node sink) {
- sink = any(JwtParse jwtParse).getTokenArg() or
- sink = any(JwtParseWithKeyFunction jwtParseWithKeyFunction).getTokenArg()
- }
-
- predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
- golangJwtIsAdditionalFlowStep(nodeFrom, nodeTo)
- or
- goJoseIsAdditionalFlowStep(nodeFrom, nodeTo)
- }
-}
-
-module NoValidationConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) {
- source instanceof UntrustedFlowSource and
- not WithValidation::flow(source, _)
- }
-
- predicate isSink(DataFlow::Node sink) {
- sink = any(JwtUnverifiedParse parseUnverified).getTokenArg()
- }
-
- predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
- golangJwtIsAdditionalFlowStep(nodeFrom, nodeTo)
- or
- goJoseIsAdditionalFlowStep(nodeFrom, nodeTo)
- }
-}
-
-module WithValidation = TaintTracking::Global;
-
-module NoValidation = TaintTracking::Global;
-
-import NoValidation::PathGraph
-
-from NoValidation::PathNode source, NoValidation::PathNode sink
-where NoValidation::flowPath(source, sink)
-select sink.getNode(), source, sink,
- "This JWT is parsed without verification and received from $@.", source.getNode(),
- "this user-controlled source"
diff --git a/go/ql/test/experimental/CWE-347/ParseJWTWithoutVerification.qlref b/go/ql/test/experimental/CWE-347/ParseJWTWithoutVerification.qlref
deleted file mode 100644
index a4326ff97e6..00000000000
--- a/go/ql/test/experimental/CWE-347/ParseJWTWithoutVerification.qlref
+++ /dev/null
@@ -1 +0,0 @@
-experimental/CWE-347/ParseJWTWithoutVerification.ql
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-347/ParseJWTWithoutVerification.expected b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected
similarity index 100%
rename from go/ql/test/experimental/CWE-347/ParseJWTWithoutVerification.expected
rename to go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected
diff --git a/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref
new file mode 100644
index 00000000000..53caf5633a7
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref
@@ -0,0 +1 @@
+Security/CWE-347/MissingJwtSignatureCheck.ql
diff --git a/go/ql/test/experimental/CWE-347/go-jose.v3.go b/go/ql/test/query-tests/Security/CWE-347/go-jose.v3.go
similarity index 100%
rename from go/ql/test/experimental/CWE-347/go-jose.v3.go
rename to go/ql/test/query-tests/Security/CWE-347/go-jose.v3.go
diff --git a/go/ql/test/experimental/CWE-347/go.mod b/go/ql/test/query-tests/Security/CWE-347/go.mod
similarity index 100%
rename from go/ql/test/experimental/CWE-347/go.mod
rename to go/ql/test/query-tests/Security/CWE-347/go.mod
diff --git a/go/ql/test/experimental/CWE-347/golang-jwt-v5.go b/go/ql/test/query-tests/Security/CWE-347/golang-jwt-v5.go
similarity index 100%
rename from go/ql/test/experimental/CWE-347/golang-jwt-v5.go
rename to go/ql/test/query-tests/Security/CWE-347/golang-jwt-v5.go
diff --git a/go/ql/test/experimental/CWE-347/vendor/github.com/go-jose/go-jose/v3/jwt/stub.go b/go/ql/test/query-tests/Security/CWE-347/vendor/github.com/go-jose/go-jose/v3/jwt/stub.go
similarity index 100%
rename from go/ql/test/experimental/CWE-347/vendor/github.com/go-jose/go-jose/v3/jwt/stub.go
rename to go/ql/test/query-tests/Security/CWE-347/vendor/github.com/go-jose/go-jose/v3/jwt/stub.go
diff --git a/go/ql/test/experimental/CWE-347/vendor/github.com/golang-jwt/jwt/v5/stub.go b/go/ql/test/query-tests/Security/CWE-347/vendor/github.com/golang-jwt/jwt/v5/stub.go
similarity index 100%
rename from go/ql/test/experimental/CWE-347/vendor/github.com/golang-jwt/jwt/v5/stub.go
rename to go/ql/test/query-tests/Security/CWE-347/vendor/github.com/golang-jwt/jwt/v5/stub.go
diff --git a/go/ql/test/experimental/CWE-347/vendor/modules.txt b/go/ql/test/query-tests/Security/CWE-347/vendor/modules.txt
similarity index 100%
rename from go/ql/test/experimental/CWE-347/vendor/modules.txt
rename to go/ql/test/query-tests/Security/CWE-347/vendor/modules.txt
From ad7d40f0af7219f854818eaf41bb11c910d123bf Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 12 Feb 2024 12:41:01 +0100
Subject: [PATCH 02/11] Add missing QLDoc
---
.../lib/semmle/go/security/MissingJwtSignatureCheck.qll | 2 ++
.../security/MissingJwtSignatureCheckCustomizations.qll | 9 +++++++++
2 files changed, 11 insertions(+)
diff --git a/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll
index 346264900fb..73605d65b02 100644
--- a/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll
+++ b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheck.qll
@@ -11,6 +11,7 @@ import go
module MissingJwtSignatureCheck {
import MissingJwtSignatureCheckCustomizations::MissingJwtSignatureCheck
+ /** Config for reasoning about JWT vulnerabilities. */
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof Source and
@@ -24,6 +25,7 @@ module MissingJwtSignatureCheck {
}
}
+ /** Tracks taint flow for reasoning about JWT vulnerabilities. */
module Flow = TaintTracking::Global;
private module SafeParseConfig implements DataFlow::ConfigSig {
diff --git a/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll
index bfc2a18b3b1..2b048441151 100644
--- a/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll
+++ b/go/ql/lib/semmle/go/security/MissingJwtSignatureCheckCustomizations.qll
@@ -1,7 +1,16 @@
+/**
+ * Provides default sources, sinks, and sanitizers for reasoning about
+ * JWT vulnerabilities, as well as extension points for adding your own.
+ */
+
import go
private import semmle.go.dataflow.ExternalFlow
private import codeql.util.Unit
+/**
+ * Provides extension points for customizing the data-flow tracking configuration for reasoning
+ * about JWT vulnerabilities.
+ */
module MissingJwtSignatureCheck {
/**
* A data flow source for JWT vulnerabilities.
From 85b22a2b981d56beb4fa64ece7da418bfdfdc4a2 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 12 Feb 2024 12:41:11 +0100
Subject: [PATCH 03/11] Fix QHelp
---
go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
index 78643506041..7f2d1ac4b80 100644
--- a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
@@ -7,7 +7,7 @@
Always verify the signature by using the appropriate methods depending on the JWT library,
or use a library that verifies it by default.
-
+
The following example shows a case where a JWT is parsed without verifying the
signature.
From 551875cb5afec536dcbfd65e8067f94069c6a0cd Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 12 Feb 2024 14:42:13 +0100
Subject: [PATCH 04/11] Add 'jwt' as valid sink kind
---
shared/mad/codeql/mad/ModelValidation.qll | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll
index 03aa0337fc7..20ef0015d78 100644
--- a/shared/mad/codeql/mad/ModelValidation.qll
+++ b/shared/mad/codeql/mad/ModelValidation.qll
@@ -39,7 +39,9 @@ module KindValidation {
"mongodb.sink", "nosql-injection", "unsafe-deserialization",
// Swift-only currently, but may be shared in the future
"database-store", "format-string", "hash-iteration-count", "predicate-injection",
- "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe"
+ "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe",
+ // Go-only currently, but may be shared in the future
+ "jwt"
]
or
this.matches([
From 5a82d2188a0a1ce13179daa2d57f14b1ebe2b110 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 12 Feb 2024 14:42:26 +0100
Subject: [PATCH 05/11] Fix double quotes in MaD row
---
go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml b/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
index 8a27cc21d19..04db1290669 100644
--- a/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
+++ b/go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
@@ -18,4 +18,4 @@ extensions:
- ["github.com/dgrijalva/jwt-go", "", True, "ParseECPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
- ["github.com/dgrijalva/jwt-go", "", True, "ParseRSAPrivateKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
- ["github.com/dgrijalva/jwt-go", "", True, "ParseRSAPrivateKeyFromPEMWithPassword", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
- - ["github.com/dgrijalva/jwt-go", "", True, ParseRSAPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["github.com/dgrijalva/jwt-go", "", True, "ParseRSAPublicKeyFromPEM", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
From 769ec16803833802a8d3171d75a21c9d5d0505da Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 14 Feb 2024 09:54:16 +0100
Subject: [PATCH 06/11] Apply suggestions from code review
Co-authored-by: Chris Smowton
---
go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
index 7f2d1ac4b80..be9285b9717 100644
--- a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
@@ -2,10 +2,10 @@
Applications decoding a JSON Web Token (JWT) may be vulnerable when the
- signature is not correctly verified in the process.
+ signature is not correctly verified.
- Always verify the signature by using the appropriate methods depending on the JWT library,
+
Always verify the signature by using the appropriate methods provided by the JWT library,
or use a library that verifies it by default.
From f9638760fff2cb52b86be3aded4f51e1b9ca953d Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 14 Feb 2024 14:08:21 +0100
Subject: [PATCH 07/11] Fix MaD rows
---
go/ql/lib/ext/gopkg.in.square.go-jose.model.yml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml b/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml
index d526ac893a7..fa0c3806166 100644
--- a/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml
+++ b/go/ql/lib/ext/gopkg.in.square.go-jose.model.yml
@@ -3,12 +3,12 @@ extensions:
pack: codeql/go-all
extensible: sinkModel
data:
- - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "JSONWebToken", True, "UnsafeClaimsWithoutVerification", "", "", "Argument[-1]", "jwt", "manual"]
+ - ["gopkg.in/square/go-jose.v2/jwt", "JSONWebToken", True, "UnsafeClaimsWithoutVerification", "", "", "Argument[-1]", "jwt", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
data:
- - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "", True, "ParseEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
- - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "", True, "ParseSigned", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
- - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "NestedJSONWebToken", True, "ParseSignedAndEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
- - ["gopkg.in/square/go-jose/$ANYVERSION/jwt", "NestedJSONWebToken", True, "Decrypt", "", "", "Argument[-1]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose.v2/jwt", "", True, "ParseEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose.v2/jwt", "", True, "ParseSigned", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose.v2/jwt", "NestedJSONWebToken", True, "ParseSignedAndEncrypted", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
+ - ["gopkg.in/square/go-jose.v2/jwt", "NestedJSONWebToken", True, "Decrypt", "", "", "Argument[-1]", "ReturnValue[0]", "taint", "manual"]
From 582f341d9e920d95c279a4607b14e8e1efe0b2f6 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 14 Feb 2024 14:17:32 +0100
Subject: [PATCH 08/11] Add references to qhelp
---
.../Security/CWE-347/MissingJwtSignatureCheck.qhelp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
index be9285b9717..5c899f01d5d 100644
--- a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
@@ -5,8 +5,8 @@
signature is not correctly verified.
- Always verify the signature by using the appropriate methods provided by the JWT library,
- or use a library that verifies it by default.
+ Always verify the signature by using the appropriate methods provided by the JWT
+ library, or use a library that verifies it by default.
The following example shows a case where a JWT is parsed without verifying the
@@ -17,9 +17,9 @@
-
-
-
+ JWT IO: Introduction to JSON Web Tokens.
+ jwt-go: Documentation.
+ Go JOSE: Documentation.
\ No newline at end of file
From dd39fa0bdec8334d856526718bbb74e90d37b314 Mon Sep 17 00:00:00 2001
From: Jeroen Ketema
Date: Fri, 16 Feb 2024 15:03:52 +0100
Subject: [PATCH 09/11] C++: Support C++20 range-based for initializers
---
.../exprparents.ql | 19 +
.../for_initialization.ql | 9 +
.../old.dbscheme | 2244 +++++++++++++++++
.../semmlecode.cpp.dbscheme | 2241 ++++++++++++++++
.../stmtparents.ql | 20 +
.../upgrade.properties | 5 +
...2023-02-16-range-based-for-initializers.md | 4 +
cpp/ql/lib/semmle/code/cpp/PrintAST.qll | 6 +-
.../code/cpp/controlflow/internal/CFG.qll | 18 +-
.../raw/internal/TranslatedStmt.qll | 31 +-
cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll | 32 +-
cpp/ql/lib/semmlecode.cpp.dbscheme | 5 +-
.../exprparents.ql | 19 +
.../old.dbscheme | 2241 ++++++++++++++++
.../semmlecode.cpp.dbscheme | 2244 +++++++++++++++++
.../stmtparents.ql | 15 +
.../upgrade.properties | 4 +
.../library-tests/ir/ir/PrintAST.expected | 25 +-
.../library-tests/ir/ir/aliased_ir.expected | 129 +-
.../ir/ir/aliased_ssa_consistency.expected | 1 -
.../aliased_ssa_consistency_unsound.expected | 1 -
.../ir/ir/operand_locations.expected | 134 +-
.../ir/ir/raw_consistency.expected | 1 -
.../test/library-tests/ir/ir/raw_ir.expected | 97 +-
.../ir/ir/unaliased_ssa_consistency.expected | 1 -
...unaliased_ssa_consistency_unsound.expected | 1 -
.../forstmt/rangebasedforstmt/cfg.expected | 85 +
.../forstmt/rangebasedforstmt/cfg.ql | 28 +
.../forstmt/rangebasedforstmt/forstmt.h | 12 +
.../forstmt/rangebasedforstmt/forstmt01.cpp | 9 +
.../forstmt/rangebasedforstmt/forstmt02.cpp | 12 +
31 files changed, 9498 insertions(+), 195 deletions(-)
create mode 100644 cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/exprparents.ql
create mode 100644 cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/for_initialization.ql
create mode 100644 cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/old.dbscheme
create mode 100644 cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/semmlecode.cpp.dbscheme
create mode 100644 cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/stmtparents.ql
create mode 100644 cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/upgrade.properties
create mode 100644 cpp/ql/lib/change-notes/2023-02-16-range-based-for-initializers.md
create mode 100644 cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/exprparents.ql
create mode 100644 cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/old.dbscheme
create mode 100644 cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/semmlecode.cpp.dbscheme
create mode 100644 cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/stmtparents.ql
create mode 100644 cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/upgrade.properties
create mode 100644 cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.expected
create mode 100644 cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.ql
create mode 100644 cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt.h
create mode 100644 cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt01.cpp
create mode 100644 cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt02.cpp
diff --git a/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/exprparents.ql b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/exprparents.ql
new file mode 100644
index 00000000000..9d2071ae1f7
--- /dev/null
+++ b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/exprparents.ql
@@ -0,0 +1,19 @@
+class Element extends @element {
+ string toString() { none() }
+}
+
+class Expr extends @expr {
+ string toString() { none() }
+}
+
+class Stmt extends @stmt {
+ string toString() { none() }
+}
+
+predicate isStmtWithInitializer(Stmt stmt) { exists(int kind | stmts(stmt, kind, _) | kind = 29) }
+
+from Expr child, int index, int index_new, Element parent
+where
+ exprparents(child, index, parent) and
+ if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index
+select child, index_new, parent
diff --git a/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/for_initialization.ql b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/for_initialization.ql
new file mode 100644
index 00000000000..6f09ce7e17d
--- /dev/null
+++ b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/for_initialization.ql
@@ -0,0 +1,9 @@
+class Stmt extends @stmt {
+ string toString() { none() }
+}
+
+from Stmt f, Stmt i
+where
+ for_initialization(f, i) and
+ f instanceof @stmt_for
+select f, i
diff --git a/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/old.dbscheme b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/old.dbscheme
new file mode 100644
index 00000000000..298438feb14
--- /dev/null
+++ b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/old.dbscheme
@@ -0,0 +1,2244 @@
+
+/**
+ * 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(
+ 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 source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string 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
+ */
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+@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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+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 @macroinvocation.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_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+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
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref,
+ int handle: @variable ref,
+ int promise: @variable ref
+);
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ 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
+);
+
+#keyset[id, type_id]
+var_decls(
+ 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
+)
+is_structured_binding(unique int id: @variable 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,
+ int enclosing : @element 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
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function 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 = @errortype
+| 2 = @unknowntype
+| 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 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+| 40 = @decimal32 // _Decimal32
+| 41 = @decimal64 // _Decimal64
+| 42 = @decimal128 // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+;
+
+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
+);
+
+/**
+ * An instance of the C++11 `decltype` operator. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+ 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 // classic C: typedef typedef type name
+| 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
+| 14 = @using_alias // a using name = type style typedef
+;
+*/
+
+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,
+ string uuid: string ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean 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
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr 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 frontend.
+ 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
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr 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
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr 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
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+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_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr 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`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ 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
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ ;
+
+/*
+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;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ 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
+);
+
+braced_initialisers(
+ int init: @initialiser 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 // frontend 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
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ ;
+
+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. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: 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 ;
+
+@access = @varaccess | @routineexpr ;
+
+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
+| 37 = @stmt_co_return
+;
+
+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_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt 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_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_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
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_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
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
+for_initialization(
+ unique int for_stmt: @stmt_for_or_range_based_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 ;
+
+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(
+ 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/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/semmlecode.cpp.dbscheme b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/semmlecode.cpp.dbscheme
new file mode 100644
index 00000000000..4f9fabab512
--- /dev/null
+++ b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/semmlecode.cpp.dbscheme
@@ -0,0 +1,2241 @@
+
+/**
+ * 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(
+ 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 source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string 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
+ */
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+@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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+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 @macroinvocation.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_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+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
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref,
+ int handle: @variable ref,
+ int promise: @variable ref
+);
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ 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
+);
+
+#keyset[id, type_id]
+var_decls(
+ 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
+)
+is_structured_binding(unique int id: @variable 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,
+ int enclosing : @element 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
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function 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 = @errortype
+| 2 = @unknowntype
+| 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 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+| 40 = @decimal32 // _Decimal32
+| 41 = @decimal64 // _Decimal64
+| 42 = @decimal128 // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+;
+
+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
+);
+
+/**
+ * An instance of the C++11 `decltype` operator. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+ 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 // classic C: typedef typedef type name
+| 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
+| 14 = @using_alias // a using name = type style typedef
+;
+*/
+
+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,
+ string uuid: string ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean 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
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr 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 frontend.
+ 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
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr 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
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr 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
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+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_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr 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`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ 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
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ ;
+
+/*
+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;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ 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
+);
+
+braced_initialisers(
+ int init: @initialiser 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 // frontend 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
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ ;
+
+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. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: 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 ;
+
+@access = @varaccess | @routineexpr ;
+
+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
+| 37 = @stmt_co_return
+;
+
+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_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt 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_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_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
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_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 ;
+
+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(
+ 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/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/stmtparents.ql b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/stmtparents.ql
new file mode 100644
index 00000000000..3e26873debb
--- /dev/null
+++ b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/stmtparents.ql
@@ -0,0 +1,20 @@
+class Element extends @element {
+ string toString() { none() }
+}
+
+class Stmt extends @stmt {
+ string toString() { none() }
+}
+
+predicate isStmtWithInitializer(Stmt stmt) { exists(int kind | stmts(stmt, kind, _) | kind = 29) }
+
+from Stmt child, int index, int index_new, Element parent
+where
+ stmtparents(child, index, parent) and
+ (
+ not isStmtWithInitializer(parent)
+ or
+ index > 0
+ ) and
+ if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index
+select child, index_new, parent
diff --git a/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/upgrade.properties b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/upgrade.properties
new file mode 100644
index 00000000000..8c7ed37ab4f
--- /dev/null
+++ b/cpp/downgrades/298438feb146335af824002589cd6d4e96e5dbf9/upgrade.properties
@@ -0,0 +1,5 @@
+description: Support C++20 range-based for initializers
+compatibility: partial
+exprparents.rel: run exprparents.qlo
+stmtparents.rel: run stmtparents.qlo
+for_initialization.rel: run for_initialization.qlo
diff --git a/cpp/ql/lib/change-notes/2023-02-16-range-based-for-initializers.md b/cpp/ql/lib/change-notes/2023-02-16-range-based-for-initializers.md
new file mode 100644
index 00000000000..ba85ec7f155
--- /dev/null
+++ b/cpp/ql/lib/change-notes/2023-02-16-range-based-for-initializers.md
@@ -0,0 +1,4 @@
+---
+category: feature
+---
+* A `getInitialization` predicate was added to the `RangeBasedForStmt` class that yields the C++20-style initializer of the range-based `for` statement when it exists.
diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll
index 68023574c3a..fa894a8b0fb 100644
--- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll
+++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll
@@ -735,7 +735,9 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
or
s.(ForStmt).getStmt() = e and pred = "getStmt()"
or
- s.(RangeBasedForStmt).getChild(0) = e and pred = "getChild(0)"
+ s.(RangeBasedForStmt).getInitialization() = e and pred = "getInitialization()"
+ or
+ s.(RangeBasedForStmt).getChild(1) = e and pred = "getChild(1)"
or
s.(RangeBasedForStmt).getBeginEndDeclaration() = e and pred = "getBeginEndDeclaration()"
or
@@ -743,7 +745,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
or
s.(RangeBasedForStmt).getUpdate() = e and pred = "getUpdate()"
or
- s.(RangeBasedForStmt).getChild(4) = e and pred = "getChild(4)"
+ s.(RangeBasedForStmt).getChild(5) = e and pred = "getChild(5)"
or
s.(RangeBasedForStmt).getStmt() = e and pred = "getStmt()"
or
diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll
index 32d9cb9bce4..c003ec4595e 100644
--- a/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll
+++ b/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll
@@ -637,8 +637,10 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
any(RangeBasedForStmt for |
i = -1 and ni = for and spec.isAt()
or
+ i = 0 and ni = for.getInitialization() and spec.isAround()
+ or
exists(DeclStmt s | s.getADeclaration() = for.getRangeVariable() |
- i = 0 and ni = s and spec.isAround()
+ i = 1 and ni = s and spec.isAround()
)
or
exists(DeclStmt s |
@@ -649,22 +651,22 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
// DeclStmt in that case.
exists(s.getADeclaration())
|
- i = 1 and ni = s and spec.isAround()
+ i = 2 and ni = s and spec.isAround()
)
or
- i = 2 and ni = for.getCondition() and spec.isBefore()
+ i = 3 and ni = for.getCondition() and spec.isBefore()
or
- i = 3 and /* BARRIER */ ni = for and spec.isBarrier()
+ i = 4 and /* BARRIER */ ni = for and spec.isBarrier()
or
exists(DeclStmt declStmt | declStmt.getADeclaration() = for.getVariable() |
- i = 4 and ni = declStmt and spec.isAfter()
+ i = 5 and ni = declStmt and spec.isAfter()
)
or
- i = 5 and ni = for.getStmt() and spec.isAround()
+ i = 6 and ni = for.getStmt() and spec.isAround()
or
- i = 6 and ni = for.getUpdate() and spec.isAround()
+ i = 7 and ni = for.getUpdate() and spec.isAround()
or
- i = 7 and ni = for.getCondition() and spec.isBefore()
+ i = 8 and ni = for.getCondition() and spec.isBefore()
)
or
scope =
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
index eff4593b335..a7d12052392 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll
@@ -960,25 +960,38 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override RangeBasedForStmt stmt;
override TranslatedElement getChild(int id) {
- id = 0 and result = this.getRangeVariableDeclStmt()
+ id = 0 and result = this.getInitialization()
+ or
+ id = 1 and result = this.getRangeVariableDeclStmt()
or
// Note: `__begin` and `__end` are declared by the same `DeclStmt`
- id = 1 and result = this.getBeginEndVariableDeclStmt()
+ id = 2 and result = this.getBeginEndVariableDeclStmt()
or
- id = 2 and result = this.getCondition()
+ id = 3 and result = this.getCondition()
or
- id = 3 and result = this.getUpdate()
+ id = 4 and result = this.getUpdate()
or
- id = 4 and result = this.getVariableDeclStmt()
+ id = 5 and result = this.getVariableDeclStmt()
or
- id = 5 and result = this.getBody()
+ id = 6 and result = this.getBody()
+ }
+
+ private predicate hasInitialization() { exists(stmt.getInitialization()) }
+
+ private TranslatedStmt getInitialization() {
+ result = getTranslatedStmt(stmt.getInitialization())
}
override Instruction getFirstInstruction(EdgeKind kind) {
- result = this.getRangeVariableDeclStmt().getFirstInstruction(kind)
+ if this.hasInitialization()
+ then result = this.getInitialization().getFirstInstruction(kind)
+ else result = this.getFirstRangeVariableDeclStmtInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
+ child = this.getInitialization() and
+ result = this.getFirstRangeVariableDeclStmtInstruction(kind)
+ or
child = this.getRangeVariableDeclStmt() and
result = this.getBeginEndVariableDeclStmt().getFirstInstruction(kind)
or
@@ -1018,6 +1031,10 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
)
}
+ private Instruction getFirstRangeVariableDeclStmtInstruction(EdgeKind kind) {
+ result = this.getRangeVariableDeclStmt().getFirstInstruction(kind)
+ }
+
private TranslatedDeclStmt getBeginEndVariableDeclStmt() {
exists(IRVariableDeclarationEntry entry |
entry.getStmt() = stmt.getBeginEndDeclaration() and
diff --git a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
index 13046d79a7a..b161da47620 100644
--- a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
+++ b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
@@ -892,6 +892,26 @@ class DoStmt extends Loop, @stmt_end_test_while {
class RangeBasedForStmt extends Loop, @stmt_range_based_for {
override string getAPrimaryQlClass() { result = "RangeBasedForStmt" }
+ /**
+ * Gets the initialization statement of this 'for' statement, if any.
+ *
+ * For example, for
+ * ```
+ * for (int x = y; auto z : ... ) { }
+ * ```
+ * the result is `int x = y;`.
+ *
+ * Does not hold if the initialization statement is missing or an empty statement, as in
+ * ```
+ * for (auto z : ...) { }
+ * ```
+ * or
+ * ```
+ * for (; auto z : ) { }
+ * ```
+ */
+ Stmt getInitialization() { for_initialization(underlyingElement(this), unresolveElement(result)) }
+
/**
* Gets the 'body' statement of this range-based 'for' statement.
*
@@ -901,7 +921,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* ```
* the result is the `BlockStmt` `{ y += x; }`.
*/
- override Stmt getStmt() { result = this.getChild(5) }
+ override Stmt getStmt() { result = this.getChild(6) }
override string toString() { result = "for(...:...) ..." }
@@ -914,7 +934,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* ```
* the result is `int x`.
*/
- LocalVariable getVariable() { result = this.getChild(4).(DeclStmt).getADeclaration() }
+ LocalVariable getVariable() { result = this.getChild(5).(DeclStmt).getADeclaration() }
/**
* Gets the expression giving the range to iterate over.
@@ -928,7 +948,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
Expr getRange() { result = this.getRangeVariable().getInitializer().getExpr() }
/** Gets the compiler-generated `__range` variable after desugaring. */
- LocalVariable getRangeVariable() { result = this.getChild(0).(DeclStmt).getADeclaration() }
+ LocalVariable getRangeVariable() { result = this.getChild(1).(DeclStmt).getADeclaration() }
/**
* Gets the compiler-generated `__begin != __end` which is the
@@ -936,7 +956,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* It will be either an `NEExpr` or a call to a user-defined
* `operator!=`.
*/
- override Expr getCondition() { result = this.getChild(2) }
+ override Expr getCondition() { result = this.getChild(3) }
override Expr getControllingExpr() { result = this.getCondition() }
@@ -945,7 +965,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* `__end`, initializing them to the values they have before entering the
* desugared loop.
*/
- DeclStmt getBeginEndDeclaration() { result = this.getChild(1) }
+ DeclStmt getBeginEndDeclaration() { result = this.getChild(2) }
/** Gets the compiler-generated `__begin` variable after desugaring. */
LocalVariable getBeginVariable() { result = this.getBeginEndDeclaration().getDeclaration(0) }
@@ -959,7 +979,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* be either a `PrefixIncrExpr` or a call to a user-defined
* `operator++`.
*/
- Expr getUpdate() { result = this.getChild(3) }
+ Expr getUpdate() { result = this.getChild(4) }
/** Gets the compiler-generated `__begin` variable after desugaring. */
LocalVariable getAnIterationVariable() { result = this.getBeginVariable() }
diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme
index 4f9fabab512..298438feb14 100644
--- a/cpp/ql/lib/semmlecode.cpp.dbscheme
+++ b/cpp/ql/lib/semmlecode.cpp.dbscheme
@@ -2050,8 +2050,11 @@ switch_body(
int body_id: @stmt ref
);
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
for_initialization(
- unique int for_stmt: @stmt_for ref,
+ unique int for_stmt: @stmt_for_or_range_based_for ref,
int init_id: @stmt ref
);
diff --git a/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/exprparents.ql b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/exprparents.ql
new file mode 100644
index 00000000000..eb72780d7b2
--- /dev/null
+++ b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/exprparents.ql
@@ -0,0 +1,19 @@
+class Element extends @element {
+ string toString() { none() }
+}
+
+class Expr extends @expr {
+ string toString() { none() }
+}
+
+class Stmt extends @stmt {
+ string toString() { none() }
+}
+
+predicate isStmtWithInitializer(Stmt stmt) { exists(int kind | stmts(stmt, kind, _) | kind = 29) }
+
+from Expr child, int index, int index_new, Element parent
+where
+ exprparents(child, index, parent) and
+ if isStmtWithInitializer(parent) then index_new = index + 1 else index_new = index
+select child, index_new, parent
diff --git a/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/old.dbscheme b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/old.dbscheme
new file mode 100644
index 00000000000..4f9fabab512
--- /dev/null
+++ b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/old.dbscheme
@@ -0,0 +1,2241 @@
+
+/**
+ * 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(
+ 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 source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string 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
+ */
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+@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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+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 @macroinvocation.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_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+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
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref,
+ int handle: @variable ref,
+ int promise: @variable ref
+);
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ 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
+);
+
+#keyset[id, type_id]
+var_decls(
+ 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
+)
+is_structured_binding(unique int id: @variable 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,
+ int enclosing : @element 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
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function 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 = @errortype
+| 2 = @unknowntype
+| 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 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+| 40 = @decimal32 // _Decimal32
+| 41 = @decimal64 // _Decimal64
+| 42 = @decimal128 // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+;
+
+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
+);
+
+/**
+ * An instance of the C++11 `decltype` operator. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+ 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 // classic C: typedef typedef type name
+| 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
+| 14 = @using_alias // a using name = type style typedef
+;
+*/
+
+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,
+ string uuid: string ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean 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
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr 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 frontend.
+ 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
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr 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
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr 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
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+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_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr 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`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ 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
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ ;
+
+/*
+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;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ 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
+);
+
+braced_initialisers(
+ int init: @initialiser 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 // frontend 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
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ ;
+
+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. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: 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 ;
+
+@access = @varaccess | @routineexpr ;
+
+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
+| 37 = @stmt_co_return
+;
+
+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_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt 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_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_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
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_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 ;
+
+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(
+ 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/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/semmlecode.cpp.dbscheme
new file mode 100644
index 00000000000..298438feb14
--- /dev/null
+++ b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/semmlecode.cpp.dbscheme
@@ -0,0 +1,2244 @@
+
+/**
+ * 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(
+ 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 source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string 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
+ */
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+@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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+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
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+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 @macroinvocation.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_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+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
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref,
+ int handle: @variable ref,
+ int promise: @variable ref
+);
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ 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
+);
+
+#keyset[id, type_id]
+var_decls(
+ 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
+)
+is_structured_binding(unique int id: @variable 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,
+ int enclosing : @element 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
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function 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 = @errortype
+| 2 = @unknowntype
+| 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 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+| 40 = @decimal32 // _Decimal32
+| 41 = @decimal64 // _Decimal64
+| 42 = @decimal128 // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+;
+
+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
+);
+
+/**
+ * An instance of the C++11 `decltype` operator. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+ 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 // classic C: typedef typedef type name
+| 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
+| 14 = @using_alias // a using name = type style typedef
+;
+*/
+
+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,
+ string uuid: string ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean 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
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr 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 frontend.
+ 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
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr 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
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr 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
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+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_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr 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`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ 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
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ ;
+
+/*
+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;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ 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
+);
+
+braced_initialisers(
+ int init: @initialiser 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 // frontend 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
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ ;
+
+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. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: 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 ;
+
+@access = @varaccess | @routineexpr ;
+
+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
+| 37 = @stmt_co_return
+;
+
+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_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt 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_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_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
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_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
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
+for_initialization(
+ unique int for_stmt: @stmt_for_or_range_based_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 ;
+
+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(
+ 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/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/stmtparents.ql b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/stmtparents.ql
new file mode 100644
index 00000000000..e69ab3f6679
--- /dev/null
+++ b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/stmtparents.ql
@@ -0,0 +1,15 @@
+class Element extends @element {
+ string toString() { none() }
+}
+
+class Stmt extends @stmt {
+ string toString() { none() }
+}
+
+predicate isStmtWithInitializer(Stmt stmt) { exists(int kind | stmts(stmt, kind, _) | kind = 29) }
+
+from Stmt child, int index, int index_new, Element parent
+where
+ stmtparents(child, index, parent) and
+ if isStmtWithInitializer(parent) then index_new = index + 1 else index_new = index
+select child, index_new, parent
diff --git a/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/upgrade.properties b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/upgrade.properties
new file mode 100644
index 00000000000..9eb5a30ee50
--- /dev/null
+++ b/cpp/ql/lib/upgrades/4f9fabab5124d49108782c081579f45a70571d74/upgrade.properties
@@ -0,0 +1,4 @@
+description: Support C++20 range-based for initializers
+compatibility: partial
+exprparents.rel: run exprparents.qlo
+stmtparents.rel: run stmtparents.qlo
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index 24ff484b9ec..d49a340d6e3 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -9478,7 +9478,7 @@ ir.cpp:
# 1079| Type = [LValueReferenceType] const vector &
# 1079| getEntryPoint(): [BlockStmt] { ... }
# 1080| getStmt(0): [RangeBasedForStmt] for(...:...) ...
-# 1080| getChild(0): [DeclStmt] declaration
+# 1080| getChild(1): [DeclStmt] declaration
# 1080| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
# 1080| Type = [LValueReferenceType] const vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
@@ -9535,7 +9535,7 @@ ir.cpp:
# 1080| getQualifier(): [VariableAccess] (__begin)
# 1080| Type = [NestedStruct] iterator
# 1080| ValueCategory = lvalue
-# 1080| getChild(4): [DeclStmt] declaration
+# 1080| getChild(5): [DeclStmt] declaration
# 1080| getDeclarationEntry(0): [VariableDeclarationEntry] definition of e
# 1080| Type = [IntType] int
# 1080| getVariable().getInitializer(): [Initializer] initializer for e
@@ -9571,7 +9571,7 @@ ir.cpp:
# 1080| Type = [NestedStruct] iterator
# 1080| ValueCategory = lvalue
# 1086| getStmt(1): [RangeBasedForStmt] for(...:...) ...
-# 1086| getChild(0): [DeclStmt] declaration
+# 1086| getChild(1): [DeclStmt] declaration
# 1086| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
# 1086| Type = [LValueReferenceType] const vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
@@ -9628,7 +9628,7 @@ ir.cpp:
# 1086| getQualifier(): [VariableAccess] (__begin)
# 1086| Type = [NestedStruct] iterator
# 1086| ValueCategory = lvalue
-# 1086| getChild(4): [DeclStmt] declaration
+# 1086| getChild(5): [DeclStmt] declaration
# 1086| getDeclarationEntry(0): [VariableDeclarationEntry] definition of e
# 1086| Type = [LValueReferenceType] const int &
# 1086| getVariable().getInitializer(): [Initializer] initializer for e
@@ -16520,7 +16520,20 @@ ir.cpp:
# 2152| Type = [VoidType] void
# 2152| ValueCategory = prvalue
# 2153| getStmt(5): [RangeBasedForStmt] for(...:...) ...
-# 2153| getChild(0): [DeclStmt] declaration
+# 2153| getInitialization(): [DeclStmt] declaration
+# 2153| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
+# 2153| Type = [ClassTemplateInstantiation,Struct] vector
+# 2153| getVariable().getInitializer(): [Initializer] initializer for ys
+# 2153| getExpr(): [ConstructorCall] call to vector
+# 2153| Type = [VoidType] void
+# 2153| ValueCategory = prvalue
+# 2153| getArgument(0): [VariableAccess] x
+# 2153| Type = [Class] ClassWithDestructor
+# 2153| ValueCategory = prvalue(load)
+# 2153| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2153| Type = [Class] ClassWithDestructor
+# 2153| ValueCategory = lvalue
+# 2153| getChild(1): [DeclStmt] declaration
# 2153| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__range)
# 2153| Type = [LValueReferenceType] vector &
#-----| getVariable().getInitializer(): [Initializer] initializer for (__range)
@@ -16582,7 +16595,7 @@ ir.cpp:
# 2153| getQualifier(): [VariableAccess] (__begin)
# 2153| Type = [NestedStruct] iterator
# 2153| ValueCategory = lvalue
-# 2153| getChild(4): [DeclStmt] declaration
+# 2153| getChild(5): [DeclStmt] declaration
# 2153| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 2153| Type = [Class] ClassWithDestructor
# 2153| getVariable().getInitializer(): [Initializer] initializer for y
diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
index cc972e38fc1..3dbe2065ff1 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
@@ -12708,85 +12708,98 @@ ir.cpp:
# 2152| m2152_6(unknown) = Chi : total:m2150_1, partial:m2152_5
# 2152| m2152_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2152_1
# 2152| m2152_8(ClassWithDestructor) = Chi : total:m2152_2, partial:m2152_7
-# 2153| r2153_1(glval &>) = VariableAddress[(__range)] :
-# 2153| r2153_2(glval>) = VariableAddress :
-# 2153| r2153_3(vector &) = CopyValue : r2153_2
-# 2153| m2153_4(vector &) = Store[(__range)] : &:r2153_1, r2153_3
-# 2153| r2153_5(glval) = VariableAddress[(__begin)] :
-# 2153| r2153_6(glval &>) = VariableAddress[(__range)] :
-# 2153| r2153_7(vector &) = Load[(__range)] : &:r2153_6, m2153_4
-#-----| r0_1(glval>) = CopyValue : r2153_7
-#-----| r0_2(glval>) = Convert : r0_1
-# 2153| r2153_8(glval) = FunctionAddress[begin] :
-# 2153| r2153_9(iterator) = Call[begin] : func:r2153_8, this:r0_2
+# 2153| r2153_1(glval>) = VariableAddress[ys] :
+# 2153| m2153_2(vector) = Uninitialized[ys] : &:r2153_1
+# 2153| r2153_3(glval) = FunctionAddress[vector] :
+# 2153| r2153_4(glval) = VariableAddress[#temp2153:40] :
+# 2153| r2153_5(glval) = VariableAddress[x] :
+# 2153| r2153_6(ClassWithDestructor) = Load[x] : &:r2153_5, m2152_8
+# 2153| m2153_7(ClassWithDestructor) = Store[#temp2153:40] : &:r2153_4, r2153_6
+# 2153| r2153_8(ClassWithDestructor) = Load[#temp2153:40] : &:r2153_4, m2153_7
+# 2153| v2153_9(void) = Call[vector] : func:r2153_3, this:r2153_1, 0:r2153_8
# 2153| m2153_10(unknown) = ^CallSideEffect : ~m2152_6
# 2153| m2153_11(unknown) = Chi : total:m2152_6, partial:m2153_10
-#-----| v0_3(void) = ^IndirectReadSideEffect[-1] : &:r0_2, ~m2153_11
-# 2153| m2153_12(iterator) = Store[(__begin)] : &:r2153_5, r2153_9
-# 2153| r2153_13(glval) = VariableAddress[(__end)] :
+# 2153| m2153_12(vector) = ^IndirectMayWriteSideEffect[-1] : &:r2153_1
+# 2153| m2153_13(vector) = Chi : total:m2153_2, partial:m2153_12
# 2153| r2153_14(glval &>) = VariableAddress[(__range)] :
-# 2153| r2153_15(vector &) = Load[(__range)] : &:r2153_14, m2153_4
-#-----| r0_4(glval>) = CopyValue : r2153_15
+# 2153| r2153_15(glval>) = VariableAddress[ys] :
+# 2153| r2153_16(vector &) = CopyValue : r2153_15
+# 2153| m2153_17(vector &) = Store[(__range)] : &:r2153_14, r2153_16
+# 2153| r2153_18(glval) = VariableAddress[(__begin)] :
+# 2153| r2153_19(glval &>) = VariableAddress[(__range)] :
+# 2153| r2153_20(vector &) = Load[(__range)] : &:r2153_19, m2153_17
+#-----| r0_1(glval>) = CopyValue : r2153_20
+#-----| r0_2(glval>) = Convert : r0_1
+# 2153| r2153_21(glval) = FunctionAddress[begin] :
+# 2153| r2153_22(iterator) = Call[begin] : func:r2153_21, this:r0_2
+# 2153| m2153_23(unknown) = ^CallSideEffect : ~m2153_11
+# 2153| m2153_24(unknown) = Chi : total:m2153_11, partial:m2153_23
+#-----| v0_3(void) = ^IndirectReadSideEffect[-1] : &:r0_2, m2153_13
+# 2153| m2153_25(iterator) = Store[(__begin)] : &:r2153_18, r2153_22
+# 2153| r2153_26(glval) = VariableAddress[(__end)] :
+# 2153| r2153_27(glval &>) = VariableAddress[(__range)] :
+# 2153| r2153_28(vector &) = Load[(__range)] : &:r2153_27, m2153_17
+#-----| r0_4(glval>) = CopyValue : r2153_28
#-----| r0_5(glval>) = Convert : r0_4
-# 2153| r2153_16(glval) = FunctionAddress[end] :
-# 2153| r2153_17(iterator) = Call[end] : func:r2153_16, this:r0_5
-# 2153| m2153_18(unknown) = ^CallSideEffect : ~m2153_11
-# 2153| m2153_19(unknown) = Chi : total:m2153_11, partial:m2153_18
-#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m2153_19
-# 2153| m2153_20(iterator) = Store[(__end)] : &:r2153_13, r2153_17
+# 2153| r2153_29(glval) = FunctionAddress[end] :
+# 2153| r2153_30(iterator) = Call[end] : func:r2153_29, this:r0_5
+# 2153| m2153_31(unknown) = ^CallSideEffect : ~m2153_24
+# 2153| m2153_32(unknown) = Chi : total:m2153_24, partial:m2153_31
+#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_5, m2153_13
+# 2153| m2153_33(iterator) = Store[(__end)] : &:r2153_26, r2153_30
#-----| Goto -> Block 7
# 2153| Block 7
-# 2153| m2153_21(iterator) = Phi : from 6:m2153_12, from 8:m2153_46
-# 2153| m2153_22(unknown) = Phi : from 6:~m2153_19, from 8:~m2153_43
-# 2153| r2153_23(glval) = VariableAddress[(__begin)] :
-#-----| r0_7(glval) = Convert : r2153_23
-# 2153| r2153_24(glval) = FunctionAddress[operator!=] :
-# 2153| r2153_25(glval) = VariableAddress[(__end)] :
-# 2153| r2153_26(iterator) = Load[(__end)] : &:r2153_25, m2153_20
-# 2153| r2153_27(bool) = Call[operator!=] : func:r2153_24, this:r0_7, 0:r2153_26
-# 2153| m2153_28(unknown) = ^CallSideEffect : ~m2153_22
-# 2153| m2153_29(unknown) = Chi : total:m2153_22, partial:m2153_28
-#-----| v0_8(void) = ^IndirectReadSideEffect[-1] : &:r0_7, m2153_21
-# 2153| v2153_30(void) = ConditionalBranch : r2153_27
+# 2153| m2153_34(iterator) = Phi : from 6:m2153_25, from 8:m2153_59
+# 2153| m2153_35(unknown) = Phi : from 6:~m2153_32, from 8:~m2153_56
+# 2153| r2153_36(glval) = VariableAddress[(__begin)] :
+#-----| r0_7(glval) = Convert : r2153_36
+# 2153| r2153_37(glval) = FunctionAddress[operator!=] :
+# 2153| r2153_38(glval) = VariableAddress[(__end)] :
+# 2153| r2153_39(iterator) = Load[(__end)] : &:r2153_38, m2153_33
+# 2153| r2153_40(bool) = Call[operator!=] : func:r2153_37, this:r0_7, 0:r2153_39
+# 2153| m2153_41(unknown) = ^CallSideEffect : ~m2153_35
+# 2153| m2153_42(unknown) = Chi : total:m2153_35, partial:m2153_41
+#-----| v0_8(void) = ^IndirectReadSideEffect[-1] : &:r0_7, m2153_34
+# 2153| v2153_43(void) = ConditionalBranch : r2153_40
#-----| False -> Block 9
#-----| True -> Block 8
# 2153| Block 8
-# 2153| r2153_31(glval) = VariableAddress[y] :
-# 2153| r2153_32(glval) = VariableAddress[(__begin)] :
-#-----| r0_9(glval) = Convert : r2153_32
-# 2153| r2153_33(glval) = FunctionAddress[operator*] :
-# 2153| r2153_34(ClassWithDestructor &) = Call[operator*] : func:r2153_33, this:r0_9
-# 2153| m2153_35(unknown) = ^CallSideEffect : ~m2153_29
-# 2153| m2153_36(unknown) = Chi : total:m2153_29, partial:m2153_35
-#-----| v0_10(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m2153_21
-# 2153| r2153_37(ClassWithDestructor) = Load[?] : &:r2153_34, ~m2153_36
-# 2153| m2153_38(ClassWithDestructor) = Store[y] : &:r2153_31, r2153_37
+# 2153| r2153_44(glval) = VariableAddress[y] :
+# 2153| r2153_45(glval) = VariableAddress[(__begin)] :
+#-----| r0_9(glval) = Convert : r2153_45
+# 2153| r2153_46(glval) = FunctionAddress[operator*] :
+# 2153| r2153_47(ClassWithDestructor &) = Call[operator*] : func:r2153_46, this:r0_9
+# 2153| m2153_48(unknown) = ^CallSideEffect : ~m2153_42
+# 2153| m2153_49(unknown) = Chi : total:m2153_42, partial:m2153_48
+#-----| v0_10(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m2153_34
+# 2153| r2153_50(ClassWithDestructor) = Load[?] : &:r2153_47, ~m2153_49
+# 2153| m2153_51(ClassWithDestructor) = Store[y] : &:r2153_44, r2153_50
# 2154| r2154_1(glval) = VariableAddress[y] :
# 2154| r2154_2(glval) = FunctionAddress[set_x] :
# 2154| r2154_3(char) = Constant[97] :
# 2154| v2154_4(void) = Call[set_x] : func:r2154_2, this:r2154_1, 0:r2154_3
-# 2154| m2154_5(unknown) = ^CallSideEffect : ~m2153_36
-# 2154| m2154_6(unknown) = Chi : total:m2153_36, partial:m2154_5
-# 2154| v2154_7(void) = ^IndirectReadSideEffect[-1] : &:r2154_1, m2153_38
+# 2154| m2154_5(unknown) = ^CallSideEffect : ~m2153_49
+# 2154| m2154_6(unknown) = Chi : total:m2153_49, partial:m2154_5
+# 2154| v2154_7(void) = ^IndirectReadSideEffect[-1] : &:r2154_1, m2153_51
# 2154| m2154_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2154_1
-# 2154| m2154_9(ClassWithDestructor) = Chi : total:m2153_38, partial:m2154_8
-# 2153| r2153_39(glval) = VariableAddress[(__begin)] :
-# 2153| r2153_40(glval) = FunctionAddress[operator++] :
-# 2153| r2153_41(iterator &) = Call[operator++] : func:r2153_40, this:r2153_39
-# 2153| m2153_42(unknown) = ^CallSideEffect : ~m2154_6
-# 2153| m2153_43(unknown) = Chi : total:m2154_6, partial:m2153_42
-# 2153| v2153_44(void) = ^IndirectReadSideEffect[-1] : &:r2153_39, m2153_21
-# 2153| m2153_45(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r2153_39
-# 2153| m2153_46(iterator) = Chi : total:m2153_21, partial:m2153_45
-# 2153| r2153_47(glval) = CopyValue : r2153_41
+# 2154| m2154_9(ClassWithDestructor) = Chi : total:m2153_51, partial:m2154_8
+# 2153| r2153_52(glval) = VariableAddress[(__begin)] :
+# 2153| r2153_53(glval) = FunctionAddress[operator++] :
+# 2153| r2153_54(iterator &) = Call[operator++] : func:r2153_53, this:r2153_52
+# 2153| m2153_55(unknown) = ^CallSideEffect : ~m2154_6
+# 2153| m2153_56(unknown) = Chi : total:m2154_6, partial:m2153_55
+# 2153| v2153_57(void) = ^IndirectReadSideEffect[-1] : &:r2153_52, m2153_34
+# 2153| m2153_58(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r2153_52
+# 2153| m2153_59(iterator) = Chi : total:m2153_34, partial:m2153_58
+# 2153| r2153_60(glval) = CopyValue : r2153_54
#-----| Goto (back edge) -> Block 7
# 2155| Block 9
# 2155| v2155_1(void) = NoOp :
# 2136| v2136_9(void) = ReturnVoid :
-# 2136| v2136_10(void) = AliasedUse : ~m2153_29
+# 2136| v2136_10(void) = AliasedUse : ~m2153_42
# 2136| v2136_11(void) = ExitFunction :
# 2136| Block 10
diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected
index 6e9be083ee0..b93c7d2649f 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected
@@ -28,5 +28,4 @@ nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
-| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
missingCppType
diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected
index 6e9be083ee0..b93c7d2649f 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected
@@ -28,5 +28,4 @@ nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
-| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
missingCppType
diff --git a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected
index e9ea1e95943..e3b2ea7c275 100644
--- a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected
+++ b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected
@@ -874,8 +874,10 @@
| file://:0:0:0:0 | SideEffect | m1080_23 |
| file://:0:0:0:0 | SideEffect | m1086_23 |
| file://:0:0:0:0 | SideEffect | m1086_23 |
-| file://:0:0:0:0 | SideEffect | m2153_21 |
-| file://:0:0:0:0 | SideEffect | m2153_21 |
+| file://:0:0:0:0 | SideEffect | m2153_13 |
+| file://:0:0:0:0 | SideEffect | m2153_13 |
+| file://:0:0:0:0 | SideEffect | m2153_34 |
+| file://:0:0:0:0 | SideEffect | m2153_34 |
| file://:0:0:0:0 | SideEffect | ~m0_4 |
| file://:0:0:0:0 | SideEffect | ~m0_4 |
| file://:0:0:0:0 | SideEffect | ~m0_4 |
@@ -892,8 +894,6 @@
| file://:0:0:0:0 | SideEffect | ~m1242_4 |
| file://:0:0:0:0 | SideEffect | ~m1449_6 |
| file://:0:0:0:0 | SideEffect | ~m1841_8 |
-| file://:0:0:0:0 | SideEffect | ~m2153_11 |
-| file://:0:0:0:0 | SideEffect | ~m2153_19 |
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_1 |
@@ -10194,7 +10194,7 @@
| ir.cpp:2134:54:2134:57 | StoreValue | r2134_4 |
| ir.cpp:2136:6:2136:35 | ChiPartial | partial:m2136_3 |
| ir.cpp:2136:6:2136:35 | ChiTotal | total:m2136_2 |
-| ir.cpp:2136:6:2136:35 | SideEffect | ~m2153_29 |
+| ir.cpp:2136:6:2136:35 | SideEffect | ~m2153_42 |
| ir.cpp:2136:42:2136:42 | Address | &:r2136_5 |
| ir.cpp:2136:50:2136:50 | Address | &:r2136_7 |
| ir.cpp:2137:29:2137:29 | Address | &:r2137_1 |
@@ -10289,74 +10289,90 @@
| ir.cpp:2152:25:2152:25 | ChiTotal | total:m2150_1 |
| ir.cpp:2152:25:2152:25 | ChiTotal | total:m2152_2 |
| ir.cpp:2152:25:2152:25 | SideEffect | ~m2150_1 |
-| ir.cpp:2153:5:2153:5 | Address | &:r2153_1 |
-| ir.cpp:2153:5:2153:5 | Address | &:r2153_5 |
-| ir.cpp:2153:5:2153:5 | Address | &:r2153_13 |
-| ir.cpp:2153:64:2153:64 | Address | &:r2153_31 |
-| ir.cpp:2153:68:2153:68 | Address | &:r2153_6 |
-| ir.cpp:2153:68:2153:68 | Address | &:r2153_14 |
-| ir.cpp:2153:68:2153:68 | Address | &:r2153_25 |
-| ir.cpp:2153:68:2153:68 | Address | &:r2153_34 |
-| ir.cpp:2153:68:2153:68 | Address | &:r2153_39 |
-| ir.cpp:2153:68:2153:68 | Address | &:r2153_39 |
-| ir.cpp:2153:68:2153:68 | Arg(0) | 0:r2153_26 |
+| ir.cpp:2153:5:2153:5 | Address | &:r2153_14 |
+| ir.cpp:2153:5:2153:5 | Address | &:r2153_18 |
+| ir.cpp:2153:5:2153:5 | Address | &:r2153_26 |
+| ir.cpp:2153:37:2153:38 | Address | &:r2153_1 |
+| ir.cpp:2153:37:2153:38 | Address | &:r2153_1 |
+| ir.cpp:2153:37:2153:38 | Arg(this) | this:r2153_1 |
+| ir.cpp:2153:40:2153:40 | Address | &:r2153_4 |
+| ir.cpp:2153:40:2153:40 | Address | &:r2153_4 |
+| ir.cpp:2153:40:2153:40 | Address | &:r2153_5 |
+| ir.cpp:2153:40:2153:40 | Arg(0) | 0:r2153_8 |
+| ir.cpp:2153:40:2153:40 | Load | m2152_8 |
+| ir.cpp:2153:40:2153:40 | Load | m2153_7 |
+| ir.cpp:2153:40:2153:40 | StoreValue | r2153_6 |
+| ir.cpp:2153:40:2153:41 | CallTarget | func:r2153_3 |
+| ir.cpp:2153:40:2153:41 | ChiPartial | partial:m2153_10 |
+| ir.cpp:2153:40:2153:41 | ChiPartial | partial:m2153_12 |
+| ir.cpp:2153:40:2153:41 | ChiTotal | total:m2152_6 |
+| ir.cpp:2153:40:2153:41 | ChiTotal | total:m2153_2 |
+| ir.cpp:2153:40:2153:41 | SideEffect | ~m2152_6 |
+| ir.cpp:2153:64:2153:64 | Address | &:r2153_44 |
+| ir.cpp:2153:68:2153:68 | Address | &:r2153_19 |
+| ir.cpp:2153:68:2153:68 | Address | &:r2153_27 |
+| ir.cpp:2153:68:2153:68 | Address | &:r2153_38 |
+| ir.cpp:2153:68:2153:68 | Address | &:r2153_47 |
+| ir.cpp:2153:68:2153:68 | Address | &:r2153_52 |
+| ir.cpp:2153:68:2153:68 | Address | &:r2153_52 |
+| ir.cpp:2153:68:2153:68 | Arg(0) | 0:r2153_39 |
| ir.cpp:2153:68:2153:68 | Arg(this) | this:r0_2 |
| ir.cpp:2153:68:2153:68 | Arg(this) | this:r0_5 |
| ir.cpp:2153:68:2153:68 | Arg(this) | this:r0_7 |
| ir.cpp:2153:68:2153:68 | Arg(this) | this:r0_9 |
-| ir.cpp:2153:68:2153:68 | Arg(this) | this:r2153_39 |
-| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_8 |
-| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_16 |
-| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_24 |
-| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_33 |
-| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_40 |
-| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_10 |
-| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_18 |
-| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_28 |
-| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_35 |
-| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_42 |
-| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_45 |
-| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2152_6 |
+| ir.cpp:2153:68:2153:68 | Arg(this) | this:r2153_52 |
+| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_21 |
+| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_29 |
+| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_37 |
+| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_46 |
+| ir.cpp:2153:68:2153:68 | CallTarget | func:r2153_53 |
+| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_23 |
+| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_31 |
+| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_41 |
+| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_48 |
+| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_55 |
+| ir.cpp:2153:68:2153:68 | ChiPartial | partial:m2153_58 |
| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_11 |
-| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_21 |
-| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_22 |
-| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_29 |
+| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_24 |
+| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_34 |
+| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_35 |
+| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2153_42 |
| ir.cpp:2153:68:2153:68 | ChiTotal | total:m2154_6 |
-| ir.cpp:2153:68:2153:68 | Condition | r2153_27 |
-| ir.cpp:2153:68:2153:68 | Load | m2153_4 |
-| ir.cpp:2153:68:2153:68 | Load | m2153_4 |
-| ir.cpp:2153:68:2153:68 | Load | m2153_20 |
-| ir.cpp:2153:68:2153:68 | Phi | from 6:m2153_12 |
-| ir.cpp:2153:68:2153:68 | Phi | from 6:~m2153_19 |
-| ir.cpp:2153:68:2153:68 | Phi | from 8:m2153_46 |
-| ir.cpp:2153:68:2153:68 | Phi | from 8:~m2153_43 |
-| ir.cpp:2153:68:2153:68 | SideEffect | m2153_21 |
-| ir.cpp:2153:68:2153:68 | SideEffect | ~m2152_6 |
+| ir.cpp:2153:68:2153:68 | Condition | r2153_40 |
+| ir.cpp:2153:68:2153:68 | Load | m2153_17 |
+| ir.cpp:2153:68:2153:68 | Load | m2153_17 |
+| ir.cpp:2153:68:2153:68 | Load | m2153_33 |
+| ir.cpp:2153:68:2153:68 | Phi | from 6:m2153_25 |
+| ir.cpp:2153:68:2153:68 | Phi | from 6:~m2153_32 |
+| ir.cpp:2153:68:2153:68 | Phi | from 8:m2153_59 |
+| ir.cpp:2153:68:2153:68 | Phi | from 8:~m2153_56 |
+| ir.cpp:2153:68:2153:68 | SideEffect | m2153_34 |
| ir.cpp:2153:68:2153:68 | SideEffect | ~m2153_11 |
-| ir.cpp:2153:68:2153:68 | SideEffect | ~m2153_22 |
-| ir.cpp:2153:68:2153:68 | SideEffect | ~m2153_29 |
+| ir.cpp:2153:68:2153:68 | SideEffect | ~m2153_24 |
+| ir.cpp:2153:68:2153:68 | SideEffect | ~m2153_35 |
+| ir.cpp:2153:68:2153:68 | SideEffect | ~m2153_42 |
| ir.cpp:2153:68:2153:68 | SideEffect | ~m2154_6 |
-| ir.cpp:2153:68:2153:68 | StoreValue | r2153_9 |
-| ir.cpp:2153:68:2153:68 | StoreValue | r2153_17 |
-| ir.cpp:2153:68:2153:68 | Unary | r2153_7 |
-| ir.cpp:2153:68:2153:68 | Unary | r2153_15 |
-| ir.cpp:2153:68:2153:68 | Unary | r2153_23 |
-| ir.cpp:2153:68:2153:68 | Unary | r2153_32 |
-| ir.cpp:2153:68:2153:68 | Unary | r2153_41 |
-| ir.cpp:2153:68:2153:69 | StoreValue | r2153_3 |
-| ir.cpp:2153:68:2153:69 | Unary | r2153_2 |
-| ir.cpp:2153:68:2153:70 | Load | ~m2153_36 |
-| ir.cpp:2153:68:2153:70 | StoreValue | r2153_37 |
+| ir.cpp:2153:68:2153:68 | StoreValue | r2153_22 |
+| ir.cpp:2153:68:2153:68 | StoreValue | r2153_30 |
+| ir.cpp:2153:68:2153:68 | Unary | r2153_20 |
+| ir.cpp:2153:68:2153:68 | Unary | r2153_28 |
+| ir.cpp:2153:68:2153:68 | Unary | r2153_36 |
+| ir.cpp:2153:68:2153:68 | Unary | r2153_45 |
+| ir.cpp:2153:68:2153:68 | Unary | r2153_54 |
+| ir.cpp:2153:68:2153:69 | StoreValue | r2153_16 |
+| ir.cpp:2153:68:2153:69 | Unary | r2153_15 |
+| ir.cpp:2153:68:2153:70 | Load | ~m2153_49 |
+| ir.cpp:2153:68:2153:70 | StoreValue | r2153_50 |
| ir.cpp:2154:7:2154:7 | Address | &:r2154_1 |
| ir.cpp:2154:7:2154:7 | Address | &:r2154_1 |
| ir.cpp:2154:7:2154:7 | Arg(this) | this:r2154_1 |
| ir.cpp:2154:7:2154:7 | ChiPartial | partial:m2154_8 |
-| ir.cpp:2154:7:2154:7 | ChiTotal | total:m2153_38 |
-| ir.cpp:2154:7:2154:7 | SideEffect | m2153_38 |
+| ir.cpp:2154:7:2154:7 | ChiTotal | total:m2153_51 |
+| ir.cpp:2154:7:2154:7 | SideEffect | m2153_51 |
| ir.cpp:2154:9:2154:13 | CallTarget | func:r2154_2 |
| ir.cpp:2154:9:2154:13 | ChiPartial | partial:m2154_5 |
-| ir.cpp:2154:9:2154:13 | ChiTotal | total:m2153_36 |
-| ir.cpp:2154:9:2154:13 | SideEffect | ~m2153_36 |
+| ir.cpp:2154:9:2154:13 | ChiTotal | total:m2153_49 |
+| ir.cpp:2154:9:2154:13 | SideEffect | ~m2153_49 |
| ir.cpp:2154:15:2154:17 | Arg(0) | 0:r2154_3 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected
index 2b8214652d6..aefdbf9d134 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected
@@ -37,5 +37,4 @@ nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
-| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
missingCppType
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
index 852241041c3..6f52c2bc668 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -11885,55 +11885,66 @@ ir.cpp:
# 2152| v2152_4(void) = Call[ClassWithDestructor] : func:r2152_3, this:r2152_1
# 2152| mu2152_5(unknown) = ^CallSideEffect : ~m?
# 2152| mu2152_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2152_1
-# 2153| r2153_1(glval &>) = VariableAddress[(__range)] :
-# 2153| r2153_2(glval>) = VariableAddress :
-# 2153| r2153_3(vector &) = CopyValue : r2153_2
-# 2153| mu2153_4(vector &) = Store[(__range)] : &:r2153_1, r2153_3
-# 2153| r2153_5(glval) = VariableAddress[(__begin)] :
-# 2153| r2153_6(glval &>) = VariableAddress[(__range)] :
-# 2153| r2153_7(vector &) = Load[(__range)] : &:r2153_6, ~m?
-#-----| r0_1(glval>) = CopyValue : r2153_7
-#-----| r0_2(glval>) = Convert : r0_1
-# 2153| r2153_8(glval) = FunctionAddress[begin] :
-# 2153| r2153_9(iterator) = Call[begin] : func:r2153_8, this:r0_2
+# 2153| r2153_1(glval>) = VariableAddress[ys] :
+# 2153| mu2153_2(vector) = Uninitialized[ys] : &:r2153_1
+# 2153| r2153_3(glval) = FunctionAddress[vector] :
+# 2153| r2153_4(glval) = VariableAddress[#temp2153:40] :
+# 2153| r2153_5(glval) = VariableAddress[x] :
+# 2153| r2153_6(ClassWithDestructor) = Load[x] : &:r2153_5, ~m?
+# 2153| mu2153_7(ClassWithDestructor) = Store[#temp2153:40] : &:r2153_4, r2153_6
+# 2153| r2153_8(ClassWithDestructor) = Load[#temp2153:40] : &:r2153_4, ~m?
+# 2153| v2153_9(void) = Call[vector] : func:r2153_3, this:r2153_1, 0:r2153_8
# 2153| mu2153_10(unknown) = ^CallSideEffect : ~m?
+# 2153| mu2153_11(vector) = ^IndirectMayWriteSideEffect[-1] : &:r2153_1
+# 2153| r2153_12(glval &>) = VariableAddress[(__range)] :
+# 2153| r2153_13(glval>) = VariableAddress[ys] :
+# 2153| r2153_14(vector &) = CopyValue : r2153_13
+# 2153| mu2153_15(vector &) = Store[(__range)] : &:r2153_12, r2153_14
+# 2153| r2153_16(glval) = VariableAddress[(__begin)] :
+# 2153| r2153_17(glval &>) = VariableAddress[(__range)] :
+# 2153| r2153_18(vector &) = Load[(__range)] : &:r2153_17, ~m?
+#-----| r0_1(glval>) = CopyValue : r2153_18
+#-----| r0_2(glval>) = Convert : r0_1
+# 2153| r2153_19(glval) = FunctionAddress[begin] :
+# 2153| r2153_20(iterator) = Call[begin] : func:r2153_19, this:r0_2
+# 2153| mu2153_21(unknown) = ^CallSideEffect : ~m?
#-----| v0_3(void) = ^IndirectReadSideEffect[-1] : &:r0_2, ~m?
-# 2153| mu2153_11(iterator) = Store[(__begin)] : &:r2153_5, r2153_9
-# 2153| r2153_12(glval) = VariableAddress[(__end)] :
-# 2153| r2153_13(glval &>) = VariableAddress[(__range)] :
-# 2153| r2153_14(vector &) = Load[(__range)] : &:r2153_13, ~m?
-#-----| r0_4(glval>) = CopyValue : r2153_14
+# 2153| mu2153_22(iterator) = Store[(__begin)] : &:r2153_16, r2153_20
+# 2153| r2153_23(glval) = VariableAddress[(__end)] :
+# 2153| r2153_24(glval &>) = VariableAddress[(__range)] :
+# 2153| r2153_25(vector &) = Load[(__range)] : &:r2153_24, ~m?
+#-----| r0_4(glval>) = CopyValue : r2153_25
#-----| r0_5(glval>) = Convert : r0_4
-# 2153| r2153_15(glval) = FunctionAddress[end] :
-# 2153| r2153_16(iterator) = Call[end] : func:r2153_15, this:r0_5
-# 2153| mu2153_17(unknown) = ^CallSideEffect : ~m?
+# 2153| r2153_26(glval) = FunctionAddress[end] :
+# 2153| r2153_27(iterator) = Call[end] : func:r2153_26, this:r0_5
+# 2153| mu2153_28(unknown) = ^CallSideEffect : ~m?
#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m?
-# 2153| mu2153_18(iterator) = Store[(__end)] : &:r2153_12, r2153_16
+# 2153| mu2153_29(iterator) = Store[(__end)] : &:r2153_23, r2153_27
#-----| Goto -> Block 8
# 2153| Block 8
-# 2153| r2153_19(glval) = VariableAddress[(__begin)] :
-#-----| r0_7(glval) = Convert : r2153_19
-# 2153| r2153_20(glval) = FunctionAddress[operator!=] :
-# 2153| r2153_21(glval) = VariableAddress[(__end)] :
-# 2153| r2153_22(iterator) = Load[(__end)] : &:r2153_21, ~m?
-# 2153| r2153_23(bool) = Call[operator!=] : func:r2153_20, this:r0_7, 0:r2153_22
-# 2153| mu2153_24(unknown) = ^CallSideEffect : ~m?
+# 2153| r2153_30(glval) = VariableAddress[(__begin)] :
+#-----| r0_7(glval) = Convert : r2153_30
+# 2153| r2153_31(glval) = FunctionAddress[operator!=] :
+# 2153| r2153_32(glval) = VariableAddress[(__end)] :
+# 2153| r2153_33(iterator) = Load[(__end)] : &:r2153_32, ~m?
+# 2153| r2153_34(bool) = Call[operator!=] : func:r2153_31, this:r0_7, 0:r2153_33
+# 2153| mu2153_35(unknown) = ^CallSideEffect : ~m?
#-----| v0_8(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
-# 2153| v2153_25(void) = ConditionalBranch : r2153_23
+# 2153| v2153_36(void) = ConditionalBranch : r2153_34
#-----| False -> Block 10
#-----| True -> Block 9
# 2153| Block 9
-# 2153| r2153_26(glval) = VariableAddress[y] :
-# 2153| r2153_27(glval) = VariableAddress[(__begin)] :
-#-----| r0_9(glval) = Convert : r2153_27
-# 2153| r2153_28(glval) = FunctionAddress[operator*] :
-# 2153| r2153_29(ClassWithDestructor &) = Call[operator*] : func:r2153_28, this:r0_9
-# 2153| mu2153_30(unknown) = ^CallSideEffect : ~m?
+# 2153| r2153_37(glval) = VariableAddress[y] :
+# 2153| r2153_38(glval) = VariableAddress[(__begin)] :
+#-----| r0_9(glval) = Convert : r2153_38
+# 2153| r2153_39(glval) = FunctionAddress[operator*] :
+# 2153| r2153_40(ClassWithDestructor &) = Call[operator*] : func:r2153_39, this:r0_9
+# 2153| mu2153_41(unknown) = ^CallSideEffect : ~m?
#-----| v0_10(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~m?
-# 2153| r2153_31(ClassWithDestructor) = Load[?] : &:r2153_29, ~m?
-# 2153| mu2153_32(ClassWithDestructor) = Store[y] : &:r2153_26, r2153_31
+# 2153| r2153_42(ClassWithDestructor) = Load[?] : &:r2153_40, ~m?
+# 2153| mu2153_43(ClassWithDestructor) = Store[y] : &:r2153_37, r2153_42
# 2154| r2154_1(glval) = VariableAddress[y] :
# 2154| r2154_2(glval) = FunctionAddress[set_x] :
# 2154| r2154_3(char) = Constant[97] :
@@ -11941,13 +11952,13 @@ ir.cpp:
# 2154| mu2154_5(unknown) = ^CallSideEffect : ~m?
# 2154| v2154_6(void) = ^IndirectReadSideEffect[-1] : &:r2154_1, ~m?
# 2154| mu2154_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2154_1
-# 2153| r2153_33(glval) = VariableAddress[(__begin)] :
-# 2153| r2153_34(glval) = FunctionAddress[operator++] :
-# 2153| r2153_35(iterator &) = Call[operator++] : func:r2153_34, this:r2153_33
-# 2153| mu2153_36(unknown) = ^CallSideEffect : ~m?
-# 2153| v2153_37(void) = ^IndirectReadSideEffect[-1] : &:r2153_33, ~m?
-# 2153| mu2153_38(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r2153_33
-# 2153| r2153_39(glval) = CopyValue : r2153_35
+# 2153| r2153_44(glval) = VariableAddress[(__begin)] :
+# 2153| r2153_45(glval) = FunctionAddress[operator++] :
+# 2153| r2153_46(iterator &) = Call[operator++] : func:r2153_45, this:r2153_44
+# 2153| mu2153_47(unknown) = ^CallSideEffect : ~m?
+# 2153| v2153_48(void) = ^IndirectReadSideEffect[-1] : &:r2153_44, ~m?
+# 2153| mu2153_49(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r2153_44
+# 2153| r2153_50(glval) = CopyValue : r2153_46
#-----| Goto (back edge) -> Block 8
# 2155| Block 10
diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected
index 6e9be083ee0..b93c7d2649f 100644
--- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected
+++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected
@@ -28,5 +28,4 @@ nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
-| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
missingCppType
diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected
index 6e9be083ee0..b93c7d2649f 100644
--- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected
+++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected
@@ -28,5 +28,4 @@ nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
-| ir.cpp:2153:68:2153:69 | VariableAddress: ys | Variable address instruction 'VariableAddress: ys' has no associated variable, in function '$@'. | ir.cpp:2136:6:2136:35 | void initialization_with_destructor(bool, char) | void initialization_with_destructor(bool, char) |
missingCppType
diff --git a/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.expected b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.expected
new file mode 100644
index 00000000000..50b8f1b9676
--- /dev/null
+++ b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.expected
@@ -0,0 +1,85 @@
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const iterator)... | |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const iterator)... | |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const vector)... | |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const vector)... | |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (reference dereference) | |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (reference dereference) | |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 5 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | initializer for (__range) | 4: declaration |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 9 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | initializer for (__begin) | 5: (__range) |
+| | forstmt01.cpp:3:6:3:14 | for_loop1 | 0 | 12 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | initializer for (__end) | 5: (__end) |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const iterator)... | |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const iterator)... | |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const vector)... | |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (const vector)... | |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (reference dereference) | |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 1 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | (reference dereference) | |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 8 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | initializer for (__range) | 4: declaration |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 12 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | initializer for (__begin) | 6: (__range) |
+| | forstmt02.cpp:3:6:3:14 | for_loop2 | 0 | 15 | file://:0:0:0:0 | file://:0:0:0:0 | file://:0:0:0:0 | initializer for (__end) | 6: (__end) |
+| forstmt | forstmt.h:2:8:2:8 | operator= | 2 | 1 | forstmt.h:2:8:2:8 | forstmt.h:2:8:2:8 | forstmt.h:2:8:2:8 | operator= | |
+| forstmt | forstmt.h:2:8:2:8 | operator= | 2 | 1 | forstmt.h:2:8:2:8 | forstmt.h:2:8:2:8 | forstmt.h:2:8:2:8 | operator= | |
+| forstmt | forstmt.h:3:12:3:12 | operator= | 3 | 1 | forstmt.h:3:12:3:12 | forstmt.h:3:12:3:12 | forstmt.h:3:12:3:12 | operator= | |
+| forstmt | forstmt.h:3:12:3:12 | operator= | 3 | 1 | forstmt.h:3:12:3:12 | forstmt.h:3:12:3:12 | forstmt.h:3:12:3:12 | operator= | |
+| forstmt | forstmt.h:4:19:4:28 | operator++ | 4 | 1 | forstmt.h:4:19:4:28 | forstmt.h:4:19:4:28 | forstmt.h:4:19:4:28 | operator++ | |
+| forstmt | forstmt.h:4:19:4:28 | operator++ | 4 | 1 | forstmt.h:4:19:4:28 | forstmt.h:4:19:4:28 | forstmt.h:4:19:4:28 | operator++ | |
+| forstmt | forstmt.h:5:12:5:20 | operator* | 5 | 1 | forstmt.h:5:12:5:20 | forstmt.h:5:12:5:20 | forstmt.h:5:12:5:20 | operator* | |
+| forstmt | forstmt.h:5:12:5:20 | operator* | 5 | 1 | forstmt.h:5:12:5:20 | forstmt.h:5:12:5:20 | forstmt.h:5:12:5:20 | operator* | |
+| forstmt | forstmt.h:7:14:7:23 | operator!= | 7 | 1 | forstmt.h:7:14:7:23 | forstmt.h:7:14:7:23 | forstmt.h:7:14:7:23 | operator!= | |
+| forstmt | forstmt.h:7:14:7:23 | operator!= | 7 | 1 | forstmt.h:7:14:7:23 | forstmt.h:7:14:7:23 | forstmt.h:7:14:7:23 | operator!= | |
+| forstmt | forstmt.h:10:14:10:18 | begin | 10 | 1 | forstmt.h:10:14:10:18 | forstmt.h:10:14:10:18 | forstmt.h:10:14:10:18 | begin | |
+| forstmt | forstmt.h:10:14:10:18 | begin | 10 | 1 | forstmt.h:10:14:10:18 | forstmt.h:10:14:10:18 | forstmt.h:10:14:10:18 | begin | |
+| forstmt | forstmt.h:11:14:11:16 | end | 11 | 1 | forstmt.h:11:14:11:16 | forstmt.h:11:14:11:16 | forstmt.h:11:14:11:16 | end | |
+| forstmt | forstmt.h:11:14:11:16 | end | 11 | 1 | forstmt.h:11:14:11:16 | forstmt.h:11:14:11:16 | forstmt.h:11:14:11:16 | end | |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 3 | 1 | forstmt01.cpp:3:39:9:1 | forstmt01.cpp:3:39:9:1 | forstmt01.cpp:3:39:9:1 | { ... } | 4: for(...:...) ... |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 4 | 2 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | for(...:...) ... | 4: declaration |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 4 | 3 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | declaration | 5: zs |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 4 | 6 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | declaration | 5: (__range) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 4 | 22 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | forstmt01.cpp:4:5:8:9 | declaration | 5: (__begin) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 1 | forstmt01.cpp:5:18:5:19 | forstmt01.cpp:5:18:5:19 | forstmt01.cpp:5:18:5:19 | (reference to) | |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 1 | forstmt01.cpp:5:18:6:9 | forstmt01.cpp:5:18:6:9 | forstmt01.cpp:5:18:6:9 | (reference dereference) | |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 1 | forstmt01.cpp:5:18:6:9 | forstmt01.cpp:5:18:6:9 | forstmt01.cpp:5:18:6:9 | (reference dereference) | |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 4 | forstmt01.cpp:5:18:5:19 | forstmt01.cpp:5:18:5:19 | forstmt01.cpp:5:18:5:19 | zs | 0: initializer for (__range) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 7 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | (__range) | 5: call to begin |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 8 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | call to begin | 0: initializer for (__begin) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 10 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | (__range) | 5: call to end |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 11 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | call to end | 0: initializer for (__end) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:14:5:14 | forstmt01.cpp:5:14:5:14 | forstmt01.cpp:5:14:5:14 | initializer for z | 7: { ... } |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | (__begin) | 5: call to operator!= |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | (__begin) | 5: call to operator* |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | (__begin) | 5: call to operator++ |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | (__end) | 5: (__begin) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | call to operator!= | 9: return ... |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | call to operator!= | 4: declaration |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | call to operator* | 5: initializer for z |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 5 | 22 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | forstmt01.cpp:5:18:5:18 | call to operator++ | 5: (__end) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 7 | 22 | forstmt01.cpp:7:9:8:9 | forstmt01.cpp:7:9:8:9 | forstmt01.cpp:7:9:8:9 | { ... } | 5: (__begin) |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 9 | 23 | forstmt01.cpp:9:1:9:1 | forstmt01.cpp:9:1:9:1 | forstmt01.cpp:9:1:9:1 | return ... | 9: for_loop1 |
+| forstmt01 | forstmt01.cpp:3:6:3:14 | for_loop1 | 9 | 24 | forstmt01.cpp:3:6:3:14 | forstmt01.cpp:3:6:3:14 | forstmt01.cpp:3:6:3:14 | for_loop1 | |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 3 | 1 | forstmt02.cpp:3:39:10:1 | forstmt02.cpp:3:39:10:1 | forstmt02.cpp:3:39:10:1 | { ... } | 4: for(...:...) ... |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 4 | 2 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | for(...:...) ... | 5: declaration |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 4 | 6 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | declaration | 6: zs |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 4 | 9 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | declaration | 6: (__range) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 4 | 25 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | forstmt02.cpp:4:5:9:9 | declaration | 6: (__begin) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 5 | 3 | forstmt02.cpp:5:9:5:18 | forstmt02.cpp:5:9:5:18 | forstmt02.cpp:5:9:5:18 | declaration | 5: initializer for y |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 5 | 4 | forstmt02.cpp:5:16:5:17 | forstmt02.cpp:5:16:5:17 | forstmt02.cpp:5:16:5:17 | initializer for y | 5: x |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 5 | 5 | forstmt02.cpp:5:17:5:17 | forstmt02.cpp:5:17:5:17 | forstmt02.cpp:5:17:5:17 | x | 4: declaration |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 1 | forstmt02.cpp:6:18:6:19 | forstmt02.cpp:6:18:6:19 | forstmt02.cpp:6:18:6:19 | (reference to) | |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 1 | forstmt02.cpp:6:18:7:9 | forstmt02.cpp:6:18:7:9 | forstmt02.cpp:6:18:7:9 | (reference dereference) | |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 1 | forstmt02.cpp:6:18:7:9 | forstmt02.cpp:6:18:7:9 | forstmt02.cpp:6:18:7:9 | (reference dereference) | |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 7 | forstmt02.cpp:6:18:6:19 | forstmt02.cpp:6:18:6:19 | forstmt02.cpp:6:18:6:19 | zs | 0: initializer for (__range) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 10 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | (__range) | 6: call to begin |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 11 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | call to begin | 0: initializer for (__begin) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 13 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | (__range) | 6: call to end |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 14 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | call to end | 0: initializer for (__end) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:14:6:14 | forstmt02.cpp:6:14:6:14 | forstmt02.cpp:6:14:6:14 | initializer for z | 8: { ... } |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | (__begin) | 6: call to operator!= |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | (__begin) | 6: call to operator* |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | (__begin) | 6: call to operator++ |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | (__end) | 6: (__begin) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | call to operator!= | 10: return ... |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | call to operator!= | 4: declaration |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | call to operator* | 6: initializer for z |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 6 | 25 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | forstmt02.cpp:6:18:6:18 | call to operator++ | 6: (__end) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 8 | 25 | forstmt02.cpp:8:9:9:9 | forstmt02.cpp:8:9:9:9 | forstmt02.cpp:8:9:9:9 | { ... } | 6: (__begin) |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 10 | 26 | forstmt02.cpp:10:1:10:1 | forstmt02.cpp:10:1:10:1 | forstmt02.cpp:10:1:10:1 | return ... | 10: for_loop2 |
+| forstmt02 | forstmt02.cpp:3:6:3:14 | for_loop2 | 10 | 27 | forstmt02.cpp:3:6:3:14 | forstmt02.cpp:3:6:3:14 | forstmt02.cpp:3:6:3:14 | for_loop2 | |
diff --git a/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.ql b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.ql
new file mode 100644
index 00000000000..190dd3f3fc5
--- /dev/null
+++ b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/cfg.ql
@@ -0,0 +1,28 @@
+import cpp
+
+int getCFLine(ControlFlowNode n) {
+ if n instanceof Function
+ then
+ // Functions appear at the end of the control flow, so we get
+ // nicer results if we take the last position in the function,
+ // rather than the function's position (which is the start).
+ result = max(ControlFlowNode c | c.getControlFlowScope() = n | c.getLocation().getStartLine())
+ else result = n.getLocation().getStartLine()
+}
+
+string getASuccessorOrNone(ControlFlowNode n) {
+ if exists(n.getASuccessor())
+ then
+ exists(ControlFlowNode s, string trueSucc, string falseSucc |
+ s = n.getASuccessor() and
+ (if s = n.getATrueSuccessor() then trueSucc = " " else trueSucc = "") and
+ (if s = n.getAFalseSuccessor() then falseSucc = " " else falseSucc = "") and
+ result = trueSucc + falseSucc + getCFLine(s) + ": " + s.toString()
+ )
+ else result = ""
+}
+
+from ControlFlowNode n
+select n.getLocation().getFile().getShortName(), n.getControlFlowScope(), getCFLine(n),
+ count(n.getAPredecessor*()), // This helps order things sensibly
+ n.getLocation(), n, getASuccessorOrNone(n)
diff --git a/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt.h b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt.h
new file mode 100644
index 00000000000..9333cdfc2fa
--- /dev/null
+++ b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt.h
@@ -0,0 +1,12 @@
+template
+struct vector {
+ struct iterator {
+ iterator& operator++();
+ T& operator*() const;
+
+ bool operator!=(iterator right) const;
+ };
+
+ iterator begin() const;
+ iterator end() const;
+};
diff --git a/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt01.cpp b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt01.cpp
new file mode 100644
index 00000000000..d805e807b9b
--- /dev/null
+++ b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt01.cpp
@@ -0,0 +1,9 @@
+#include "forstmt.h"
+
+void for_loop1(int x, vector zs) {
+ for (
+ auto z : zs
+ )
+ {
+ }
+}
diff --git a/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt02.cpp b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt02.cpp
new file mode 100644
index 00000000000..cbbcc3eaa41
--- /dev/null
+++ b/cpp/ql/test/successor-tests/forstmt/rangebasedforstmt/forstmt02.cpp
@@ -0,0 +1,12 @@
+#include "forstmt.h"
+
+void for_loop2(int x, vector zs) {
+ for (
+ int y = x;
+ auto z : zs
+ )
+ {
+ }
+}
+
+// semmle-extractor-options: -std=c++20
From 8b8cebd5990de27d5105c47d824b23d0588e5509 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 19 Feb 2024 08:59:03 +0100
Subject: [PATCH 10/11] Apply suggestions from code review
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
---
go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp | 6 +++---
go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
index 5c899f01d5d..e4ba5f6acd3 100644
--- a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.qhelp
@@ -9,11 +9,11 @@
library, or use a library that verifies it by default.
- The following example shows a case where a JWT is parsed without verifying the
+
The following (bad) example shows a case where a JWT is parsed without verifying the
signature.
- In the example below, the appropriate function for parsing a JWT
- and verifying its signature is used.
+ The following (good) example uses the appropriate function for parsing a JWT
+ and verifying its signature.
diff --git a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
index 3b89201b34f..de3668f2d44 100644
--- a/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
+++ b/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
@@ -1,6 +1,6 @@
/**
* @name Missing JWT signature check
- * @description Failing to check the Json Web Token (JWT) signature may allow an attacker to forge their own tokens.
+ * @description Failing to check the JSON Web Token (JWT) signature may allow an attacker to forge their own tokens.
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
From 139ef60f6926293bcdd8526bab5ff35767fd8dfc Mon Sep 17 00:00:00 2001
From: Max Schaefer
Date: Mon, 19 Feb 2024 11:47:31 +0000
Subject: [PATCH 11/11] Automodel: Release query pack.
---
java/ql/automodel/src/CHANGELOG.md | 4 ++++
java/ql/automodel/src/change-notes/released/0.0.15.md | 3 +++
java/ql/automodel/src/codeql-pack.release.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
4 files changed, 9 insertions(+), 2 deletions(-)
create mode 100644 java/ql/automodel/src/change-notes/released/0.0.15.md
diff --git a/java/ql/automodel/src/CHANGELOG.md b/java/ql/automodel/src/CHANGELOG.md
index fa718635e0c..66435f14c73 100644
--- a/java/ql/automodel/src/CHANGELOG.md
+++ b/java/ql/automodel/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.15
+
+No user-facing changes.
+
## 0.0.14
No user-facing changes.
diff --git a/java/ql/automodel/src/change-notes/released/0.0.15.md b/java/ql/automodel/src/change-notes/released/0.0.15.md
new file mode 100644
index 00000000000..7af9c05f23f
--- /dev/null
+++ b/java/ql/automodel/src/change-notes/released/0.0.15.md
@@ -0,0 +1,3 @@
+## 0.0.15
+
+No user-facing changes.
diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml
index ca29e45d0a6..dff35216fc6 100644
--- a/java/ql/automodel/src/codeql-pack.release.yml
+++ b/java/ql/automodel/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.14
+lastReleaseVersion: 0.0.15
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 1f68ac3f6ba..554902f6894 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.15-dev
+version: 0.0.16-dev
groups:
- java
- automodel