diff --git a/.github/workflows/mad_modelDiff.yml b/.github/workflows/mad_modelDiff.yml
index 3b96d903e232..45a31f406664 100644
--- a/.github/workflows/mad_modelDiff.yml
+++ b/.github/workflows/mad_modelDiff.yml
@@ -70,7 +70,7 @@ jobs:
SHORTNAME=`basename $DATABASE`
python misc/scripts/models-as-data/generate_mad.py --language java --with-summaries --with-sinks $DATABASE $SHORTNAME/$QL_VARIANT
mkdir -p $MODELS/$SHORTNAME
- mv java/ql/lib/ext/generated/$SHORTNAME/$QL_VARIANT $MODELS/$SHORTNAME
+ mv java/ql/lib/ext/generated/modelgenerator/$SHORTNAME/$QL_VARIANT $MODELS/$SHORTNAME
cd ..
}
diff --git a/.github/workflows/python-tooling.yml b/.github/workflows/python-tooling.yml
index bab1277dd03d..a3ad9900ea47 100644
--- a/.github/workflows/python-tooling.yml
+++ b/.github/workflows/python-tooling.yml
@@ -5,7 +5,7 @@ on:
paths:
- "misc/bazel/**"
- "misc/codegen/**"
- - "misc/scripts/models-as-data/bulk_generate_mad.py"
+ - "misc/scripts/models-as-data/*.py"
- "*.bazel*"
- .github/workflows/codegen.yml
- .pre-commit-config.yaml
diff --git a/Cargo.lock b/Cargo.lock
index b6456c841063..4fab55a6444f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -140,6 +140,26 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+[[package]]
+name = "bindgen"
+version = "0.72.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
+dependencies = [
+ "bitflags 2.9.4",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.12.1",
+ "log 0.4.28",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash 2.1.1",
+ "shlex",
+ "syn",
+]
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -240,9 +260,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.37"
+version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44"
+checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -250,6 +270,15 @@ dependencies = [
"shlex",
]
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.3"
@@ -328,7 +357,7 @@ dependencies = [
"chalk-derive 0.103.0",
"chalk-ir 0.103.0",
"ena",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itertools 0.12.1",
"petgraph",
"rustc-hash 1.1.0",
@@ -349,6 +378,17 @@ dependencies = [
"windows-link 0.2.0",
]
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
[[package]]
name = "clap"
version = "4.5.48"
@@ -416,6 +456,7 @@ dependencies = [
"tree-sitter",
"tree-sitter-json",
"tree-sitter-ql",
+ "yeast",
"zstd",
]
@@ -437,6 +478,25 @@ dependencies = [
"tree-sitter-ruby",
]
+[[package]]
+name = "codeql-extractor-unified"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "codeql-extractor",
+ "encoding",
+ "lazy_static",
+ "rayon",
+ "regex",
+ "serde_json",
+ "tracing",
+ "tracing-subscriber",
+ "tree-sitter",
+ "tree-sitter-embedded-template",
+ "tree-sitter-swift",
+ "yeast",
+]
+
[[package]]
name = "codeql-rust"
version = "0.1.0"
@@ -485,6 +545,15 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+[[package]]
+name = "convert_case"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
+dependencies = [
+ "unicode-segmentation",
+]
+
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -738,6 +807,12 @@ dependencies = [
"typeid",
]
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
[[package]]
name = "figment"
version = "0.10.19"
@@ -754,9 +829,9 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
-version = "0.1.1"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "fixedbitset"
@@ -786,6 +861,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@@ -870,9 +951,26 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"allocator-api2",
"equivalent",
- "foldhash",
+ "foldhash 0.1.5",
]
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash 0.2.0",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
[[package]]
name = "hashlink"
version = "0.10.0"
@@ -1059,16 +1157,25 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.11.4"
+version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
- "hashbrown 0.15.5",
+ "hashbrown 0.17.1",
"serde",
"serde_core",
]
+[[package]]
+name = "indoc"
+version = "2.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
+dependencies = [
+ "rustversion",
+]
+
[[package]]
name = "inlinable_string"
version = "0.1.15"
@@ -1198,6 +1305,16 @@ version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link 0.2.0",
+]
+
[[package]]
name = "line-index"
version = "0.1.2"
@@ -1263,6 +1380,12 @@ dependencies = [
"autocfg",
]
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -1309,6 +1432,16 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
[[package]]
name = "notify"
version = "8.2.0"
@@ -1436,6 +1569,12 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "pathdiff"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+
[[package]]
name = "pear"
version = "0.2.9"
@@ -1491,7 +1630,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
+]
+
+[[package]]
+name = "phf"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
+dependencies = [
+ "phf_shared",
+ "serde",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
+dependencies = [
+ "fastrand",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
+dependencies = [
+ "siphasher",
]
[[package]]
@@ -1536,6 +1704,25 @@ dependencies = [
"zerocopy",
]
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit 0.25.11+spec-1.1.0",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.101"
@@ -1667,7 +1854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e876bb2c3e52a8d4e6684526a2d4e81f9d028b939ee4dc5dc775fe10deb44d59"
dependencies = [
"dashmap",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"la-arena",
"ra_ap_cfg",
"ra_ap_intern",
@@ -1709,7 +1896,7 @@ checksum = "ebffdc134eccabc17209d7760cfff7fd12ed18ab6e21188c5e084b97aa38504c"
dependencies = [
"arrayvec",
"either",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itertools 0.14.0",
"ra_ap_base_db",
"ra_ap_cfg",
@@ -1739,7 +1926,7 @@ dependencies = [
"drop_bomb",
"either",
"fst",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itertools 0.14.0",
"la-arena",
"ra-ap-rustc_abi",
@@ -1808,7 +1995,7 @@ dependencies = [
"cov-mark",
"either",
"ena",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itertools 0.14.0",
"la-arena",
"oorandom",
@@ -1846,7 +2033,7 @@ dependencies = [
"crossbeam-channel",
"either",
"fst",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itertools 0.14.0",
"line-index",
"memchr",
@@ -1948,7 +2135,7 @@ version = "0.0.301"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45db9e2df587d56f0738afa89fb2c100ff7c1e9cbe49e07f6a8b62342832211b"
dependencies = [
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"ra_ap_intern",
"ra_ap_paths",
"ra_ap_span",
@@ -2107,7 +2294,7 @@ checksum = "6c174d6b9b7a7f54687df7e00c3e75ed6f082a7943a9afb1d54f33c0c12773de"
dependencies = [
"crossbeam-channel",
"fst",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"nohash-hasher",
"ra_ap_paths",
"ra_ap_stdx",
@@ -2239,6 +2426,15 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
+[[package]]
+name = "relative-path"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "rowan"
version = "0.15.15"
@@ -2252,6 +2448,57 @@ dependencies = [
"text-size",
]
+[[package]]
+name = "rquickjs"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a135375fbac5ba723bb6a48f432a72f81539cedde422f0121a86c7c4e96d8e0d"
+dependencies = [
+ "rquickjs-core",
+ "rquickjs-macro",
+]
+
+[[package]]
+name = "rquickjs-core"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bccb7121a123865c8ace4dea42e7ed84d78b90cbaf4ca32c59849d8d210c9672"
+dependencies = [
+ "hashbrown 0.16.1",
+ "phf",
+ "relative-path",
+ "rquickjs-sys",
+]
+
+[[package]]
+name = "rquickjs-macro"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89f93602cc3112c7f30bf5f29e722784232138692c7df4c52ebbac7e035d900d"
+dependencies = [
+ "convert_case",
+ "fnv",
+ "ident_case",
+ "indexmap 2.14.0",
+ "phf_generator",
+ "phf_shared",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "rquickjs-core",
+ "syn",
+]
+
+[[package]]
+name = "rquickjs-sys"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57b1b6528590d4d65dc86b5159eae2d0219709546644c66408b2441696d1d725"
+dependencies = [
+ "bindgen",
+ "cc",
+]
+
[[package]]
name = "rust-extractor-macros"
version = "0.1.0"
@@ -2317,7 +2564,7 @@ dependencies = [
"crossbeam-utils",
"hashbrown 0.15.5",
"hashlink",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"intrusive-collections",
"papaya",
"parking_lot",
@@ -2406,11 +2653,12 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.26"
+version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
dependencies = [
"serde",
+ "serde_core",
]
[[package]]
@@ -2470,7 +2718,7 @@ version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itoa",
"memchr",
"ryu",
@@ -2506,7 +2754,7 @@ dependencies = [
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"schemars 0.9.0",
"schemars 1.0.4",
"serde",
@@ -2534,7 +2782,7 @@ version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"itoa",
"ryu",
"serde",
@@ -2556,6 +2804,18 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+[[package]]
+name = "siphasher"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
+
+[[package]]
+name = "smallbitvec"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b0e903ee191d8f7a8fbf0d712c3a1699d19e04ceba5ad1eb673053c7d938a09"
+
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -2632,18 +2892,18 @@ checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d"
[[package]]
name = "thiserror"
-version = "2.0.16"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "2.0.16"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
@@ -2708,7 +2968,7 @@ dependencies = [
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.11",
- "toml_edit",
+ "toml_edit 0.22.27",
]
[[package]]
@@ -2717,13 +2977,13 @@ version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0"
dependencies = [
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"serde_core",
"serde_spanned 1.0.2",
"toml_datetime 0.7.2",
"toml_parser",
"toml_writer",
- "winnow",
+ "winnow 0.7.13",
]
[[package]]
@@ -2744,27 +3004,48 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "toml_datetime"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+dependencies = [
+ "serde_core",
+]
+
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
- "indexmap 2.11.4",
+ "indexmap 2.14.0",
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.11",
"toml_write",
- "winnow",
+ "winnow 0.7.13",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.11+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
+dependencies = [
+ "indexmap 2.14.0",
+ "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_parser",
+ "winnow 1.0.2",
]
[[package]]
name = "toml_parser"
-version = "1.0.3"
+version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
- "winnow",
+ "winnow 1.0.2",
]
[[package]]
@@ -2779,6 +3060,12 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109"
+[[package]]
+name = "topological-sort"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
+
[[package]]
name = "tracing"
version = "0.1.41"
@@ -2853,9 +3140,9 @@ dependencies = [
[[package]]
name = "tree-sitter"
-version = "0.25.9"
+version = "0.26.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccd2a058a86cfece0bf96f7cce1021efef9c8ed0e892ab74639173e5ed7a34fa"
+checksum = "887bd495d0582c5e3e0d8ece2233666169fa56a9644d172fc22ad179ab2d0538"
dependencies = [
"cc",
"regex",
@@ -2875,6 +3162,30 @@ dependencies = [
"tree-sitter-language",
]
+[[package]]
+name = "tree-sitter-generate"
+version = "0.26.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3fb2e1bdb1d5f9d23cd5fa68cf98b3bedbd223c92a2edd60bbcf30bcf7180a5"
+dependencies = [
+ "bitflags 2.9.4",
+ "dunce",
+ "indexmap 2.14.0",
+ "indoc",
+ "log 0.4.28",
+ "pathdiff",
+ "regex",
+ "regex-syntax",
+ "rquickjs",
+ "rustc-hash 2.1.1",
+ "semver",
+ "serde",
+ "serde_json",
+ "smallbitvec",
+ "thiserror",
+ "topological-sort",
+]
+
[[package]]
name = "tree-sitter-json"
version = "0.24.8"
@@ -2891,6 +3202,16 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8"
+[[package]]
+name = "tree-sitter-python"
+version = "0.23.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d065aaa27f3aaceaf60c1f0e0ac09e1cb9eb8ed28e7bcdaa52129cffc7f4b04"
+dependencies = [
+ "cc",
+ "tree-sitter-language",
+]
+
[[package]]
name = "tree-sitter-ql"
version = "0.23.1"
@@ -2911,6 +3232,15 @@ dependencies = [
"tree-sitter-language",
]
+[[package]]
+name = "tree-sitter-swift"
+version = "0.7.2"
+dependencies = [
+ "cc",
+ "tree-sitter-generate",
+ "tree-sitter-language",
+]
+
[[package]]
name = "triomphe"
version = "0.1.14"
@@ -2960,6 +3290,12 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
+[[package]]
+name = "unicode-segmentation"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
+
[[package]]
name = "unicode-xid"
version = "0.2.6"
@@ -3349,6 +3685,15 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "winnow"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "wit-bindgen"
version = "0.45.1"
@@ -3367,6 +3712,29 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
+[[package]]
+name = "yeast"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "serde",
+ "serde_json",
+ "serde_yaml",
+ "tree-sitter",
+ "tree-sitter-python",
+ "tree-sitter-ruby",
+ "yeast-macros",
+]
+
+[[package]]
+name = "yeast-macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "yoke"
version = "0.8.0"
diff --git a/Cargo.toml b/Cargo.toml
index 58a755340b9c..62eb2e7e920c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,11 @@
resolver = "2"
members = [
"shared/tree-sitter-extractor",
+ "shared/yeast",
+ "shared/yeast-macros",
"ruby/extractor",
+ "unified/extractor",
+ "unified/extractor/tree-sitter-swift",
"rust/extractor",
"rust/extractor/macros",
"rust/ast-generator",
diff --git a/MODULE.bazel b/MODULE.bazel
index 16b4a4691f8a..fd923a32e62b 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -102,6 +102,7 @@ use_repo(
tree_sitter_extractors_deps,
"vendor_ts__anyhow-1.0.100",
"vendor_ts__argfile-0.2.1",
+ "vendor_ts__cc-1.2.61",
"vendor_ts__chalk-ir-0.104.0",
"vendor_ts__chrono-0.4.42",
"vendor_ts__clap-4.5.48",
@@ -141,14 +142,18 @@ use_repo(
"vendor_ts__serde-1.0.228",
"vendor_ts__serde_json-1.0.145",
"vendor_ts__serde_with-3.14.1",
+ "vendor_ts__serde_yaml-0.9.34-deprecated",
"vendor_ts__syn-2.0.106",
"vendor_ts__toml-0.9.7",
"vendor_ts__tracing-0.1.41",
"vendor_ts__tracing-flame-0.2.0",
"vendor_ts__tracing-subscriber-0.3.20",
- "vendor_ts__tree-sitter-0.25.9",
+ "vendor_ts__tree-sitter-0.26.8",
"vendor_ts__tree-sitter-embedded-template-0.25.0",
+ "vendor_ts__tree-sitter-generate-0.26.8",
"vendor_ts__tree-sitter-json-0.24.8",
+ "vendor_ts__tree-sitter-language-0.1.5",
+ "vendor_ts__tree-sitter-python-0.23.6",
"vendor_ts__tree-sitter-ql-0.23.1",
"vendor_ts__tree-sitter-ruby-0.23.1",
"vendor_ts__triomphe-0.1.14",
diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md
index e84ba38d1801..011af903a2a2 100644
--- a/actions/ql/lib/CHANGELOG.md
+++ b/actions/ql/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.4.35
+
+No user-facing changes.
+
## 0.4.34
### Minor Analysis Improvements
diff --git a/actions/ql/lib/change-notes/2026-04-15-poisonable-steps-additions-alterations.md b/actions/ql/lib/change-notes/2026-04-15-poisonable-steps-additions-alterations.md
new file mode 100644
index 000000000000..4a28280a3c88
--- /dev/null
+++ b/actions/ql/lib/change-notes/2026-04-15-poisonable-steps-additions-alterations.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Altered 2 patterns in the `poisonable_steps` modelling. Extra sinks are detected in the following cases: scripts executed via python modules and `go run` in directories are detected as potential mechanisms of injection. For the go execution pattern, the pattern is updated to now ignore flags that occur between go and the specific command. This change may lead to more results being detected by the following queries: `actions/untrusted-checkout/high`, `actions/untrusted-checkout/critical`, `actions/untrusted-checkout-toctou/high`, `actions/untrusted-checkout-toctou/critical`, `actions/cache-poisoning/poisonable-step`, `actions/cache-poisoning/direct-cache` and `actions/artifact-poisoning/path-traversal`.
\ No newline at end of file
diff --git a/actions/ql/lib/change-notes/released/0.4.35.md b/actions/ql/lib/change-notes/released/0.4.35.md
new file mode 100644
index 000000000000..3274ffc88e4d
--- /dev/null
+++ b/actions/ql/lib/change-notes/released/0.4.35.md
@@ -0,0 +1,3 @@
+## 0.4.35
+
+No user-facing changes.
diff --git a/actions/ql/lib/codeql-pack.release.yml b/actions/ql/lib/codeql-pack.release.yml
index 69fb16e4c39f..524302c92d3e 100644
--- a/actions/ql/lib/codeql-pack.release.yml
+++ b/actions/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.4.34
+lastReleaseVersion: 0.4.35
diff --git a/actions/ql/lib/ext/config/poisonable_steps.yml b/actions/ql/lib/ext/config/poisonable_steps.yml
index 3c1aec70a240..17b1408fa7c3 100644
--- a/actions/ql/lib/ext/config/poisonable_steps.yml
+++ b/actions/ql/lib/ext/config/poisonable_steps.yml
@@ -70,7 +70,7 @@ extensions:
- ["(source|sh|bash|zsh|fish)\\s+([^\\s]+)\\b", 2]
- ["(node)\\s+([^\\s]+)(\\.js|\\.ts)\\b", 2]
- ["(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b", 2]
+ - ["(python[\\d\\.]*)\\s+-m\\s+([A-Za-z_][\\w\\.]*)\\b", 2] # eg: pythonX -m anything(dir or file)
- ["(ruby)\\s+([^\\s]+)\\.rb\\b", 2]
- - ["(go)\\s+(generate|run)\\s+([^\\s]+)\\.go\\b", 3]
+ - ["(go)\\s+(generate|run)(?:\\s+-[^\\s]+)*\\s+([^\\s]+)", 3]
- ["(dotnet)\\s+([^\\s]+)\\.csproj\\b", 2]
-
diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml
index 6e78fc546b33..cf1232c01fb4 100644
--- a/actions/ql/lib/qlpack.yml
+++ b/actions/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/actions-all
-version: 0.4.35-dev
+version: 0.4.36-dev
library: true
warnOnImplicitThis: true
dependencies:
diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md
index 96f8d2662060..0a7fa1ce8309 100644
--- a/actions/ql/src/CHANGELOG.md
+++ b/actions/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.27
+
+No user-facing changes.
+
## 0.6.26
### Major Analysis Improvements
@@ -173,7 +177,7 @@ No user-facing changes.
* `actions/if-expression-always-true/critical`
* `actions/if-expression-always-true/high`
* `actions/unnecessary-use-of-advanced-config`
-
+
* The following query has been moved from the `code-scanning` suite to the `security-extended`
suite. Any existing alerts for this query will be closed automatically unless the analysis is
configured to use the `security-extended` suite.
diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md
index 6060354b134a..a6dd437c1baf 100644
--- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md
+++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md
@@ -1,6 +1,35 @@
## Overview
-GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job.
+GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. Under certain conditions described below, attackers can take over a repository by opening malicious PRs from forks. The attacks can result in malicious code execution causing unauthorized changes to the repository or exfiltration of repository secrets and a compromise of connected systems.
+
+## Workflow Security Model
+
+In GitHub Actions, there is a distinction between unprivileged and privileged workflows. For example, a workflow with a `pull_request` trigger is unprivileged while a workflow with `pull_request_target` is privileged.
+
+This is relevant especially for PRs from forks. Normal PRs can only be submitted by people who have write access to a repository, while PRs from forks can be submitted by anyone.
+
+On a PR from a fork, an unprivileged `pull_request` workflow has only limited capabilities but a privileged `pull_request_target` workflow is much more dangerous. A privileged workflow:
+
+ * Runs in the context of the base repository
+ * Has access to organization and repository secrets (e.g., API keys, deployment tokens)
+ * Has a read/write `GITHUB_TOKEN` by default
+ * Can access private resources
+
+Certain triggers automatically grant a workflow elevated privileges:
+
+ * `pull_request_target` as described above
+ * `workflow_run`: Triggered when another workflow completes.
+ * `issue_comment`: Triggered when a comment is made on an issue or PR.
+
+## Attack Details
+
+ * A repository has a privileged workflow
+ * An attacker forks the repository and adds malicious code (e.g., in the build script)
+ * The attacker opens a PR from the fork, and, if needed, comments on the PR
+ * The workflow in the base repository checks out the forked code
+ * The workflow runs, (e.g. the build script etc.), which contains the malicious code
+
+Please note that not only build scripts can be malicious code vectors. There is a large number of other possibilities. Some of them are listed in the [LOTP](https://boostsecurityio.github.io/lotp/) catalog.
## Recommendation
@@ -133,3 +162,5 @@ jobs:
## References
- GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
+- Mitigating risks of untrusted checkout: [GitHub Docs](https://docs.github.com/en/enterprise-cloud@latest/actions/reference/security/secure-use#mitigating-the-risks-of-untrusted-code-checkout).
+- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/).
diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md
index 6060354b134a..a6dd437c1baf 100644
--- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md
+++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md
@@ -1,6 +1,35 @@
## Overview
-GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job.
+GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. Under certain conditions described below, attackers can take over a repository by opening malicious PRs from forks. The attacks can result in malicious code execution causing unauthorized changes to the repository or exfiltration of repository secrets and a compromise of connected systems.
+
+## Workflow Security Model
+
+In GitHub Actions, there is a distinction between unprivileged and privileged workflows. For example, a workflow with a `pull_request` trigger is unprivileged while a workflow with `pull_request_target` is privileged.
+
+This is relevant especially for PRs from forks. Normal PRs can only be submitted by people who have write access to a repository, while PRs from forks can be submitted by anyone.
+
+On a PR from a fork, an unprivileged `pull_request` workflow has only limited capabilities but a privileged `pull_request_target` workflow is much more dangerous. A privileged workflow:
+
+ * Runs in the context of the base repository
+ * Has access to organization and repository secrets (e.g., API keys, deployment tokens)
+ * Has a read/write `GITHUB_TOKEN` by default
+ * Can access private resources
+
+Certain triggers automatically grant a workflow elevated privileges:
+
+ * `pull_request_target` as described above
+ * `workflow_run`: Triggered when another workflow completes.
+ * `issue_comment`: Triggered when a comment is made on an issue or PR.
+
+## Attack Details
+
+ * A repository has a privileged workflow
+ * An attacker forks the repository and adds malicious code (e.g., in the build script)
+ * The attacker opens a PR from the fork, and, if needed, comments on the PR
+ * The workflow in the base repository checks out the forked code
+ * The workflow runs, (e.g. the build script etc.), which contains the malicious code
+
+Please note that not only build scripts can be malicious code vectors. There is a large number of other possibilities. Some of them are listed in the [LOTP](https://boostsecurityio.github.io/lotp/) catalog.
## Recommendation
@@ -133,3 +162,5 @@ jobs:
## References
- GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
+- Mitigating risks of untrusted checkout: [GitHub Docs](https://docs.github.com/en/enterprise-cloud@latest/actions/reference/security/secure-use#mitigating-the-risks-of-untrusted-code-checkout).
+- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/).
diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql
index 98b9aee33f77..5c2d4b3d56c8 100644
--- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql
+++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql
@@ -1,5 +1,5 @@
/**
- * @name Checkout of untrusted code in trusted context
+ * @name Checkout of untrusted code in privileged context without privileged context use
* @description Privileged workflows have read/write access to the base repository and access to secrets.
* By explicitly checking out and running the build script from a fork the untrusted code is running in an environment
* that is able to push to the base repository and to access secrets.
diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md
index 6060354b134a..a6dd437c1baf 100644
--- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md
+++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md
@@ -1,6 +1,35 @@
## Overview
-GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job.
+GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. Under certain conditions described below, attackers can take over a repository by opening malicious PRs from forks. The attacks can result in malicious code execution causing unauthorized changes to the repository or exfiltration of repository secrets and a compromise of connected systems.
+
+## Workflow Security Model
+
+In GitHub Actions, there is a distinction between unprivileged and privileged workflows. For example, a workflow with a `pull_request` trigger is unprivileged while a workflow with `pull_request_target` is privileged.
+
+This is relevant especially for PRs from forks. Normal PRs can only be submitted by people who have write access to a repository, while PRs from forks can be submitted by anyone.
+
+On a PR from a fork, an unprivileged `pull_request` workflow has only limited capabilities but a privileged `pull_request_target` workflow is much more dangerous. A privileged workflow:
+
+ * Runs in the context of the base repository
+ * Has access to organization and repository secrets (e.g., API keys, deployment tokens)
+ * Has a read/write `GITHUB_TOKEN` by default
+ * Can access private resources
+
+Certain triggers automatically grant a workflow elevated privileges:
+
+ * `pull_request_target` as described above
+ * `workflow_run`: Triggered when another workflow completes.
+ * `issue_comment`: Triggered when a comment is made on an issue or PR.
+
+## Attack Details
+
+ * A repository has a privileged workflow
+ * An attacker forks the repository and adds malicious code (e.g., in the build script)
+ * The attacker opens a PR from the fork, and, if needed, comments on the PR
+ * The workflow in the base repository checks out the forked code
+ * The workflow runs, (e.g. the build script etc.), which contains the malicious code
+
+Please note that not only build scripts can be malicious code vectors. There is a large number of other possibilities. Some of them are listed in the [LOTP](https://boostsecurityio.github.io/lotp/) catalog.
## Recommendation
@@ -133,3 +162,5 @@ jobs:
## References
- GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
+- Mitigating risks of untrusted checkout: [GitHub Docs](https://docs.github.com/en/enterprise-cloud@latest/actions/reference/security/secure-use#mitigating-the-risks-of-untrusted-code-checkout).
+- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/).
diff --git a/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements-helpfile.md b/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements-helpfile.md
new file mode 100644
index 000000000000..2555bc03d3d1
--- /dev/null
+++ b/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements-helpfile.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Fixed help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Previously the messages were unclear as to why and how the vulnerabilities could occur.
\ No newline at end of file
diff --git a/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements-metadata.md b/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements-metadata.md
new file mode 100644
index 000000000000..78f97da0f17c
--- /dev/null
+++ b/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements-metadata.md
@@ -0,0 +1,4 @@
+---
+category: queryMetadata
+---
+* Adjusted the name of `actions/untrusted-checkout/high` to more clearly describe which parts of the scenario are in a privileged context.
\ No newline at end of file
diff --git a/actions/ql/src/change-notes/released/0.6.27.md b/actions/ql/src/change-notes/released/0.6.27.md
new file mode 100644
index 000000000000..52d3a10fd1f9
--- /dev/null
+++ b/actions/ql/src/change-notes/released/0.6.27.md
@@ -0,0 +1,3 @@
+## 0.6.27
+
+No user-facing changes.
diff --git a/actions/ql/src/codeql-pack.release.yml b/actions/ql/src/codeql-pack.release.yml
index e83bac0046e3..0748b12112f0 100644
--- a/actions/ql/src/codeql-pack.release.yml
+++ b/actions/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.6.26
+lastReleaseVersion: 0.6.27
diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml
index c815afc498c8..2c9811c780ad 100644
--- a/actions/ql/src/qlpack.yml
+++ b/actions/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/actions-queries
-version: 0.6.27-dev
+version: 0.6.28-dev
library: false
warnOnImplicitThis: true
groups: [actions, queries]
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index 2cd1bcede35e..828b87791179 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 10.1.0
+
+### New Features
+
+* A new predicate `getSwitchCase` was added to the `SwitchStmt` class, which yields the `n`th `case` statement from a `switch` statement.
+* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C and C++](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-cpp/).
+
+### Minor Analysis Improvements
+
+* Added taint flow models for the `Strsafe.h` header from the Windows SDK.
+
## 10.0.0
### Breaking Changes
diff --git a/cpp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md b/cpp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md
deleted file mode 100644
index 30f0092a4e95..000000000000
--- a/cpp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: feature
----
-* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C and C++](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-cpp/).
diff --git a/cpp/ql/lib/change-notes/released/10.1.0.md b/cpp/ql/lib/change-notes/released/10.1.0.md
new file mode 100644
index 000000000000..45d153b4896e
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/10.1.0.md
@@ -0,0 +1,10 @@
+## 10.1.0
+
+### New Features
+
+* A new predicate `getSwitchCase` was added to the `SwitchStmt` class, which yields the `n`th `case` statement from a `switch` statement.
+* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C and C++](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-cpp/).
+
+### Minor Analysis Improvements
+
+* Added taint flow models for the `Strsafe.h` header from the Windows SDK.
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 28758256b943..a85b2d36d7c5 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 10.0.0
+lastReleaseVersion: 10.1.0
diff --git a/cpp/ql/lib/ext/Strsafe.model.yml b/cpp/ql/lib/ext/Strsafe.model.yml
new file mode 100644
index 000000000000..44013854a067
--- /dev/null
+++ b/cpp/ql/lib/ext/Strsafe.model.yml
@@ -0,0 +1,94 @@
+# Models for strsafe.h safe string functions
+extensions:
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: sourceModel
+ data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
+ # StringCchGets: (pszDest, cchDest)
+ - ["", "", False, "StringCchGetsA", "", "", "Argument[*0]", "local", "manual"]
+ - ["", "", False, "StringCchGetsW", "", "", "Argument[*0]", "local", "manual"]
+ # StringCbGets: (pszDest, cbDest)
+ - ["", "", False, "StringCbGetsA", "", "", "Argument[*0]", "local", "manual"]
+ - ["", "", False, "StringCbGetsW", "", "", "Argument[*0]", "local", "manual"]
+ # StringCchGetsEx: (pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags)
+ - ["", "", False, "StringCchGetsExA", "", "", "Argument[*0]", "local", "manual"]
+ - ["", "", False, "StringCchGetsExW", "", "", "Argument[*0]", "local", "manual"]
+ # StringCbGetsEx: (pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags)
+ - ["", "", False, "StringCbGetsExA", "", "", "Argument[*0]", "local", "manual"]
+ - ["", "", False, "StringCbGetsExW", "", "", "Argument[*0]", "local", "manual"]
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: summaryModel
+ data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
+ # StringCchCopy: (pszDest, cchDest, pszSrc)
+ - ["", "", False, "StringCchCopyA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCopyW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCopy: (pszDest, cbDest, pszSrc)
+ - ["", "", False, "StringCbCopyA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCopyW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCopyEx: (pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags)
+ - ["", "", False, "StringCchCopyExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCopyExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCopyEx: (pszDest, cbDest, pszSrc, ppszDestEnd, pcbRemaining, dwFlags)
+ - ["", "", False, "StringCbCopyExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCopyExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCopyN: (pszDest, cchDest, pszSrc, cchToCopy)
+ - ["", "", False, "StringCchCopyNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCopyNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCopyN: (pszDest, cbDest, pszSrc, cbToCopy)
+ - ["", "", False, "StringCbCopyNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCopyNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCopyNEx: (pszDest, cchDest, pszSrc, cchToCopy, ppszDestEnd, pcchRemaining, dwFlags)
+ - ["", "", False, "StringCchCopyNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCopyNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCopyNEx: (pszDest, cbDest, pszSrc, cbToCopy, ppszDestEnd, pcbRemaining, dwFlags)
+ - ["", "", False, "StringCbCopyNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCopyNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCat: (pszDest, cchDest, pszSrc)
+ - ["", "", False, "StringCchCatA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCatW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCat: (pszDest, cbDest, pszSrc)
+ - ["", "", False, "StringCbCatA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCatW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCatEx: (pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags)
+ - ["", "", False, "StringCchCatExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCatExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCatEx: (pszDest, cbDest, pszSrc, ppszDestEnd, pcbRemaining, dwFlags)
+ - ["", "", False, "StringCbCatExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCatExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCatN: (pszDest, cchDest, pszSrc, cchToAppend)
+ - ["", "", False, "StringCchCatNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCatNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCatN: (pszDest, cbDest, pszSrc, cbToAppend)
+ - ["", "", False, "StringCbCatNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCatNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchCatNEx: (pszDest, cchDest, pszSrc, cchToAppend, ppszDestEnd, pcchRemaining, dwFlags)
+ - ["", "", False, "StringCchCatNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchCatNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbCatNEx: (pszDest, cbDest, pszSrc, cbToAppend, ppszDestEnd, pcbRemaining, dwFlags)
+ - ["", "", False, "StringCbCatNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbCatNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchPrintf: (pszDest, cchDest, pszFormat, ...)
+ - ["", "", False, "StringCchPrintfA", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchPrintfW", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
+ # StringCbPrintf: (pszDest, cbDest, pszFormat, ...)
+ - ["", "", False, "StringCbPrintfA", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbPrintfW", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
+ # StringCchPrintfEx: (pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, ...)
+ - ["", "", False, "StringCchPrintfExA", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchPrintfExW", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
+ # StringCbPrintfEx: (pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, ...)
+ - ["", "", False, "StringCbPrintfExA", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbPrintfExW", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
+ # StringCchVPrintf: (pszDest, cchDest, pszFormat, argList)
+ - ["", "", False, "StringCchVPrintfA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchVPrintfW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCbVPrintf: (pszDest, cbDest, pszFormat, argList)
+ - ["", "", False, "StringCbVPrintfA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbVPrintfW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
+ # StringCchVPrintfEx: (pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList)
+ - ["", "", False, "StringCchVPrintfExA", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCchVPrintfExW", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
+ # StringCbVPrintfEx: (pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, argList)
+ - ["", "", False, "StringCbVPrintfExA", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "StringCbVPrintfExW", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
diff --git a/cpp/ql/lib/ext/generated/brotli/brotli.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/brotli/brotli.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/brotli/brotli.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/brotli/brotli.model.yml
diff --git a/cpp/ql/lib/ext/generated/curl/curl.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/curl/curl.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/curl/curl.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/curl/curl.model.yml
diff --git a/cpp/ql/lib/ext/generated/glibc/glibc.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/glibc/glibc.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/glibc/glibc.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/glibc/glibc.model.yml
diff --git a/cpp/ql/lib/ext/generated/libidn2/libidn2.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/libidn2/libidn2.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/libidn2/libidn2.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/libidn2/libidn2.model.yml
diff --git a/cpp/ql/lib/ext/generated/libssh2/libssh2.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/libssh2/libssh2.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/libssh2/libssh2.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/libssh2/libssh2.model.yml
diff --git a/cpp/ql/lib/ext/generated/libuv/libuv.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/libuv/libuv.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/libuv/libuv.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/libuv/libuv.model.yml
diff --git a/cpp/ql/lib/ext/generated/nghttp2/nghttp2.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/nghttp2/nghttp2.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/nghttp2/nghttp2.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/nghttp2/nghttp2.model.yml
diff --git a/cpp/ql/lib/ext/generated/openssl/openssl.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/openssl/openssl.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/openssl/openssl.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/openssl/openssl.model.yml
diff --git a/cpp/ql/lib/ext/generated/sqlite/sqlite.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/sqlite/sqlite.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/sqlite/sqlite.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/sqlite/sqlite.model.yml
diff --git a/cpp/ql/lib/ext/generated/zlib/zlib.model.yml b/cpp/ql/lib/ext/generated/modelgenerator/zlib/zlib.model.yml
similarity index 100%
rename from cpp/ql/lib/ext/generated/zlib/zlib.model.yml
rename to cpp/ql/lib/ext/generated/modelgenerator/zlib/zlib.model.yml
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 8a9d60a7fa94..88d4dafaebb1 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 10.0.1-dev
+version: 10.1.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
index cd7504612444..ccda6c4d592d 100644
--- a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
+++ b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
@@ -1412,9 +1412,9 @@ private int indexOfSwitchCaseRank(BlockStmt b, int rnk) {
* switch (i)
* {
* case 5:
- * ...
+ * ...
* default:
- * ...
+ * ...
* }
* ```
*/
@@ -1516,8 +1516,10 @@ class SwitchCase extends Stmt, @stmt_switch_case {
* which has result `default:`, which has no result.
*/
SwitchCase getNextSwitchCase() {
- result.getSwitchStmt() = this.getSwitchStmt() and
- result.getChildNum() = this.getChildNum() + 1
+ exists(SwitchStmt s, int n |
+ this = s.getSwitchCase(n) and
+ result = s.getSwitchCase(n + 1)
+ )
}
/**
@@ -1707,9 +1709,9 @@ class SwitchCase extends Stmt, @stmt_switch_case {
* switch (i)
* {
* case 5:
- * ...
+ * ...
* default:
- * ...
+ * ...
* }
* ```
*/
@@ -1731,9 +1733,9 @@ class DefaultCase extends SwitchCase {
* switch (i)
* {
* case 5:
- * ...
+ * ...
* default:
- * ...
+ * ...
* }
* ```
*/
@@ -1768,10 +1770,10 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
* For example, for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
- * default:
+ * default:
* break;
* }
* ```
@@ -1790,20 +1792,20 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
* For example, for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
- * default:
+ * default:
* break;
* }
* ```
* the result is
* ```
* {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
- * default:
+ * default:
* break;
* }
* ```
@@ -1816,10 +1818,10 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
* For example, for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
- * default:
+ * default:
* break;
* }
* ```
@@ -1827,6 +1829,23 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
*/
SwitchCase getASwitchCase() { switch_case(underlyingElement(this), _, unresolveElement(result)) }
+ /**
+ * Gets the `n`th 'switch case' statement of this 'switch' statement, where
+ * `n` is 0-based.
+ *
+ * For example, for
+ * ```
+ * switch(i) {
+ * case 5:
+ * case 6:
+ * default:
+ * } * ```
+ * 0 yields `case 5:`, 1 yields `case 6:`, and 2 yields `default:`.
+ */
+ SwitchCase getSwitchCase(int n) {
+ switch_case(underlyingElement(this), n, unresolveElement(result))
+ }
+
/**
* Gets the 'default case' statement of this 'switch' statement,
* if any.
@@ -1834,18 +1853,18 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
* For example, for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
- * default:
+ * default:
* break;
* }
* ```
* the result is `default:`, but there is no result for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
* }
* ```
@@ -1858,18 +1877,18 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
* For example, this holds for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
- * default:
+ * default:
* break;
* }
* ```
* but not for
* ```
* switch(i) {
- * case 1:
- * case 2:
+ * case 1:
+ * case 2:
* break;
* }
* ```
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index 80b9ad0e4753..3a9d4fae927b 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.6.2
+
+No user-facing changes.
+
## 1.6.1
### Minor Analysis Improvements
@@ -7,7 +11,7 @@
* The "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
* The "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
* The "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
-* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision. However, for `build mode: none` databases, it no longer produces any results. The results in this mode were found to be very noisy and fundamentally imprecise.
+* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision. However, for `build-mode: none` databases, it no longer produces any results. The results in this mode were found to be very noisy and fundamentally imprecise.
## 1.6.0
@@ -366,7 +370,7 @@ No user-facing changes.
### Minor Analysis Improvements
* The "non-constant format string" query (`cpp/non-constant-format`) has been updated to produce fewer false positives.
-* Added dataflow models for the `gettext` function variants.
+* Added dataflow models for the `gettext` function variants.
## 0.9.4
diff --git a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
index 0a52a2b0ff4c..4bc58eb08540 100644
--- a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
+++ b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
@@ -227,6 +227,30 @@ class IgnorableUnaryBitwiseOperation extends IgnorableOperation instanceof Unary
class IgnorableAssignmentBitwiseOperation extends IgnorableOperation instanceof AssignBitwiseOperation
{ }
+class YearFieldAssignmentNode extends DataFlow::Node {
+ YearFieldAccess access;
+
+ YearFieldAssignmentNode() {
+ exists(Function f |
+ f = this.getEnclosingCallable().getUnderlyingCallable() and not f instanceof IgnorableFunction
+ |
+ this.asDefinition().(Assignment).getLValue() = access
+ or
+ this.asDefinition().(CrementOperation).getOperand() = access
+ or
+ exists(Call c | c.getAnArgument() = access and this.asDefiningArgument() = access)
+ or
+ exists(Call c, AddressOfExpr aoe |
+ c.getAnArgument() = aoe and
+ aoe.getOperand() = access and
+ this.asDefiningArgument() = aoe
+ )
+ )
+ }
+
+ YearFieldAccess getYearFieldAccess() { result = access }
+}
+
/**
* An arithmetic operation where one of the operands is a pointer or char type, ignore it
*/
@@ -287,24 +311,7 @@ predicate isOperationSourceCandidate(Expr e) {
}
/**
- * A data flow that tracks an ignorable operation (such as a bitwise operation) to an operation source, so we may disqualify it.
- */
-module IgnorableOperationToOperationSourceCandidateConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node n) { n.asExpr() instanceof IgnorableOperation }
-
- predicate isSink(DataFlow::Node n) { isOperationSourceCandidate(n.asExpr()) }
-
- // looking for sources and sinks in the same function
- DataFlow::FlowFeature getAFeature() {
- result instanceof DataFlow::FeatureEqualSourceSinkCallContext
- }
-}
-
-module IgnorableOperationToOperationSourceCandidateFlow =
- TaintTracking::Global;
-
-/**
- * The set of all expressions which is a candidate expression and also does not flow from to to some ignorable expression (eg. bitwise op)
+ * The set of all expressions that are candidate expression.
* ```
* a = something <<< 2;
* myDate.year = a + 1; // invalid
@@ -314,49 +321,16 @@ module IgnorableOperationToOperationSourceCandidateFlow =
* ```
*/
class OperationSource extends Expr {
- OperationSource() {
- isOperationSourceCandidate(this) and
- // If the candidate came from an ignorable operation, ignore the candidate
- // NOTE: we cannot easily flow the candidate to an ignorable operation as that can
- // be tricky in practice, e.g., a mod operation on a year would be part of a leap year check
- // but a mod operation ending in a year is more indicative of something to ignore (a conversion)
- not exists(IgnorableOperationToOperationSourceCandidateFlow::PathNode sink |
- sink.getNode().asExpr() = this and
- sink.isSink()
- )
- }
-}
-
-class YearFieldAssignmentNode extends DataFlow::Node {
- YearFieldAccess access;
-
- YearFieldAssignmentNode() {
- exists(Function f |
- f = this.getEnclosingCallable().getUnderlyingCallable() and not f instanceof IgnorableFunction
- ) and
- (
- this.asDefinition().(Assignment).getLValue() = access
- or
- this.asDefinition().(CrementOperation).getOperand() = access
- or
- exists(Call c | c.getAnArgument() = access and this.asDefiningArgument() = access)
- or
- exists(Call c, AddressOfExpr aoe |
- c.getAnArgument() = aoe and
- aoe.getOperand() = access and
- this.asDefiningArgument() = aoe
- )
- )
- }
-
- YearFieldAccess getYearFieldAccess() { result = access }
+ OperationSource() { isOperationSourceCandidate(this) }
}
/**
- * A DataFlow configuration for identifying flows from an identified source
- * to the Year field of a date object.
+ * An initial DataFlow configuration for identifying flows from an identified source
+ * to the Year field of a date object. This is used to restrict the sinks of
+ * `IgnorableOperationToOperationSourceCandidateConfig` and the sinks of the
+ * final `OperationToYearAssignmentConfig`.
*/
-module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
+module OperationToYearAssignmentConfig0 implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof OperationSource }
predicate isSink(DataFlow::Node n) {
@@ -411,6 +385,62 @@ module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
predicate isBarrierOut(DataFlow::Node n) { isSink(n) }
}
+module OperationToYearAssignmentFlow0 = TaintTracking::Global;
+
+predicate yearAssignmentFlowsFromSource(DataFlow::Node source, DataFlow::Node sink) {
+ OperationToYearAssignmentFlow0::flow(source, sink)
+}
+
+/**
+ * A data flow that tracks an ignorable operation (such as a bitwise operation) to an operation source, so we may disqualify it.
+ * Sinks are restricted to operation source candidates that have a flow to a year assignment in `OperationToYearAssignmentFlow0`.
+ */
+module IgnorableOperationToOperationSourceCandidateConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof IgnorableOperation }
+
+ predicate isSink(DataFlow::Node n) {
+ isOperationSourceCandidate(n.asExpr()) and
+ yearAssignmentFlowsFromSource(n, _)
+ }
+
+ // looking for sources and sinks in the same function
+ DataFlow::FlowFeature getAFeature() {
+ result instanceof DataFlow::FeatureEqualSourceSinkCallContext
+ }
+}
+
+module IgnorableOperationToOperationSourceCandidateFlow =
+ TaintTracking::Global;
+
+/**
+ * The final DataFlow configuration that refines `OperationToYearAssignmentConfig0` by
+ * additionally filtering out operation sources that flow from an ignorable operation
+ * (via `IgnorableOperationToOperationSourceCandidateFlow`).
+ */
+module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { yearAssignmentFlowsFromSource(n, _) }
+
+ predicate isSink(DataFlow::Node n) {
+ exists(DataFlow::Node operation |
+ yearAssignmentFlowsFromSource(operation, n) and
+ // If the candidate came from an ignorable operation, ignore the candidate
+ // NOTE: we cannot easily flow the candidate to an ignorable operation as that can
+ // be tricky in practice, e.g., a mod operation on a year would be part of a leap year check
+ // but a mod operation ending in a year is more indicative of something to ignore (a conversion)
+ not exists(IgnorableOperationToOperationSourceCandidateFlow::PathNode sink |
+ sink.getNode() = operation and
+ sink.isSink()
+ )
+ )
+ }
+
+ predicate isBarrier(DataFlow::Node n) { OperationToYearAssignmentConfig0::isBarrier(n) }
+
+ predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
+
+ predicate isBarrierOut(DataFlow::Node n) { isSink(n) }
+}
+
module OperationToYearAssignmentFlow = TaintTracking::Global;
predicate isLeapYearCheckSink(DataFlow::Node sink) {
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp
index 90a98e1bf573..d6c612abc759 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp
@@ -14,7 +14,7 @@ function may behave unpredictably.
This may indicate a misspelled function name, or that the required header containing
the function declaration has not been included.
-
Note: This query is not compatible with build mode: none databases, and produces
+
Note: This query is not compatible with build-mode: none databases, and produces
no results on those databases.
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
index 00b29efbd0f2..8e921faf2117 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
@@ -18,7 +18,7 @@ import TooManyArguments
import semmle.code.cpp.commons.Exclusions
/*
- * This query is not compatible with build mode: none databases, and produces
+ * This query is not compatible with build-mode: none databases, and produces
* no results on those databases.
*/
diff --git a/cpp/ql/src/change-notes/released/1.6.1.md b/cpp/ql/src/change-notes/released/1.6.1.md
index 83781b87c584..02ca1c2cd064 100644
--- a/cpp/ql/src/change-notes/released/1.6.1.md
+++ b/cpp/ql/src/change-notes/released/1.6.1.md
@@ -7,4 +7,4 @@
* The "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
* The "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
* The "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
-* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision. However, for `build mode: none` databases, it no longer produces any results. The results in this mode were found to be very noisy and fundamentally imprecise.
+* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision. However, for `build-mode: none` databases, it no longer produces any results. The results in this mode were found to be very noisy and fundamentally imprecise.
diff --git a/cpp/ql/src/change-notes/released/1.6.2.md b/cpp/ql/src/change-notes/released/1.6.2.md
new file mode 100644
index 000000000000..bbe3747556fb
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.6.2.md
@@ -0,0 +1,3 @@
+## 1.6.2
+
+No user-facing changes.
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index ef7a789e0cf1..5f5beb68311a 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.6.1
+lastReleaseVersion: 1.6.2
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 714167434c8a..ddd0014f2e02 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 1.6.2-dev
+version: 1.6.3-dev
groups:
- cpp
- queries
diff --git a/cpp/ql/test/library-tests/builtins/complex/builtin.expected b/cpp/ql/test/library-tests/builtins/complex/builtin.expected
index c1b9b18a4126..2537ff065ac6 100644
--- a/cpp/ql/test/library-tests/builtins/complex/builtin.expected
+++ b/cpp/ql/test/library-tests/builtins/complex/builtin.expected
@@ -1,4 +1,4 @@
| complex.c:3:23:3:51 | __builtin_complex | file://:0:0:0:0 | _Complex double | complex.c:3:41:3:44 | real | file://:0:0:0:0 | double | complex.c:3:47:3:50 | imag | file://:0:0:0:0 | double |
-| complex.c:4:23:4:57 | __builtin_complex | file://:0:0:0:0 | _Complex double | complex.c:4:41:4:47 | 2.71828000000000003 | file://:0:0:0:0 | double | complex.c:4:50:4:56 | 3.141589999999999883 | file://:0:0:0:0 | double |
+| complex.c:4:23:4:57 | __builtin_complex | file://:0:0:0:0 | _Complex double | complex.c:4:41:4:47 | 2.71828 | file://:0:0:0:0 | double | complex.c:4:50:4:56 | 3.14159 | file://:0:0:0:0 | double |
| complex.c:8:22:8:52 | __builtin_complex | file://:0:0:0:0 | _Complex float | complex.c:8:40:8:44 | realf | file://:0:0:0:0 | float | complex.c:8:47:8:51 | imagf | file://:0:0:0:0 | float |
-| complex.c:9:22:9:52 | __builtin_complex | file://:0:0:0:0 | _Complex float | complex.c:9:40:9:44 | 1.230000019 | file://:0:0:0:0 | float | complex.c:9:47:9:51 | 4.559999943 | file://:0:0:0:0 | float |
+| complex.c:9:22:9:52 | __builtin_complex | file://:0:0:0:0 | _Complex float | complex.c:9:40:9:44 | 1.23 | file://:0:0:0:0 | float | complex.c:9:47:9:51 | 4.56 | file://:0:0:0:0 | float |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected
index 4d78c4016dab..f6833ab4ff13 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected
@@ -298,16 +298,16 @@
| test.c:182:8:182:34 | ! ... | ! ... == 1 when ! ... is true |
| test.c:182:8:182:34 | ! ... | ... && ... != 0 when ! ... is false |
| test.c:182:8:182:34 | ! ... | ... && ... == 0 when ! ... is true |
-| test.c:182:10:182:20 | ... >= ... | 9.999999999999999547e-07 < foo+1 when ... >= ... is true |
-| test.c:182:10:182:20 | ... >= ... | 9.999999999999999547e-07 >= foo+1 when ... >= ... is false |
+| test.c:182:10:182:20 | ... >= ... | 1.0E-6 < foo+1 when ... >= ... is true |
+| test.c:182:10:182:20 | ... >= ... | 1.0E-6 >= foo+1 when ... >= ... is false |
| test.c:182:10:182:20 | ... >= ... | ... >= ... != 0 when ... >= ... is true |
| test.c:182:10:182:20 | ... >= ... | ... >= ... != 1 when ... >= ... is false |
| test.c:182:10:182:20 | ... >= ... | ... >= ... == 0 when ... >= ... is false |
| test.c:182:10:182:20 | ... >= ... | ... >= ... == 1 when ... >= ... is true |
-| test.c:182:10:182:20 | ... >= ... | foo < 9.999999999999999547e-07+0 when ... >= ... is false |
-| test.c:182:10:182:20 | ... >= ... | foo >= 9.999999999999999547e-07+0 when ... >= ... is true |
+| test.c:182:10:182:20 | ... >= ... | foo < 1.0E-6+0 when ... >= ... is false |
+| test.c:182:10:182:20 | ... >= ... | foo >= 1.0E-6+0 when ... >= ... is true |
| test.c:182:10:182:33 | ... && ... | 1.0 >= foo+1 when ... && ... is true |
-| test.c:182:10:182:33 | ... && ... | 9.999999999999999547e-07 < foo+1 when ... && ... is true |
+| test.c:182:10:182:33 | ... && ... | 1.0E-6 < foo+1 when ... && ... is true |
| test.c:182:10:182:33 | ... && ... | ! ... != 0 when ... && ... is false |
| test.c:182:10:182:33 | ... && ... | ! ... != 1 when ... && ... is true |
| test.c:182:10:182:33 | ... && ... | ! ... == 0 when ... && ... is true |
@@ -319,7 +319,7 @@
| test.c:182:10:182:33 | ... && ... | ... >= ... != 0 when ... && ... is true |
| test.c:182:10:182:33 | ... && ... | ... >= ... == 1 when ... && ... is true |
| test.c:182:10:182:33 | ... && ... | foo < 1.0+0 when ... && ... is true |
-| test.c:182:10:182:33 | ... && ... | foo >= 9.999999999999999547e-07+0 when ... && ... is true |
+| test.c:182:10:182:33 | ... && ... | foo >= 1.0E-6+0 when ... && ... is true |
| test.c:182:25:182:33 | ... < ... | 1.0 < foo+1 when ... < ... is false |
| test.c:182:25:182:33 | ... < ... | 1.0 >= foo+1 when ... < ... is true |
| test.c:182:25:182:33 | ... < ... | ... < ... != 0 when ... < ... is true |
diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected
index 5a364e3deaad..cf99d2c20b8d 100644
--- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected
+++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected
@@ -169,12 +169,12 @@ binary
| test.c:176:8:176:15 | ! ... | test.c:176:14:176:14 | b | < | test.c:176:10:176:10 | a | 1 | test.c:176:18:178:5 | { ... } |
| test.c:176:10:176:14 | ... < ... | test.c:176:10:176:10 | a | >= | test.c:176:14:176:14 | b | 0 | test.c:176:18:178:5 | { ... } |
| test.c:176:10:176:14 | ... < ... | test.c:176:14:176:14 | b | < | test.c:176:10:176:10 | a | 1 | test.c:176:18:178:5 | { ... } |
-| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 9.999999999999999547e-07 | 0 | test.c:181:25:182:20 | { ... } |
-| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 9.999999999999999547e-07 | 0 | test.c:182:25:182:33 | foo |
-| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 9.999999999999999547e-07 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } |
-| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 9.999999999999999547e-07 | < | test.c:182:10:182:12 | foo | 1 | test.c:182:25:182:33 | foo |
-| test.c:182:10:182:33 | ... && ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 9.999999999999999547e-07 | 0 | test.c:181:25:182:20 | { ... } |
-| test.c:182:10:182:33 | ... && ... | test.c:182:17:182:20 | 9.999999999999999547e-07 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } |
+| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 1.0E-6 | 0 | test.c:181:25:182:20 | { ... } |
+| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 1.0E-6 | 0 | test.c:182:25:182:33 | foo |
+| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 1.0E-6 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } |
+| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 1.0E-6 | < | test.c:182:10:182:12 | foo | 1 | test.c:182:25:182:33 | foo |
+| test.c:182:10:182:33 | ... && ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 1.0E-6 | 0 | test.c:181:25:182:20 | { ... } |
+| test.c:182:10:182:33 | ... && ... | test.c:182:17:182:20 | 1.0E-6 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } |
| test.c:182:10:182:33 | ... && ... | test.c:182:25:182:27 | foo | < | test.c:182:31:182:33 | 1.0 | 0 | test.c:181:25:182:20 | { ... } |
| test.c:182:10:182:33 | ... && ... | test.c:182:31:182:33 | 1.0 | >= | test.c:182:25:182:27 | foo | 1 | test.c:181:25:182:20 | { ... } |
| test.c:182:25:182:33 | ... < ... | test.c:182:25:182:27 | foo | < | test.c:182:31:182:33 | 1.0 | 0 | test.c:181:25:182:20 | { ... } |
diff --git a/cpp/ql/test/library-tests/dataflow/source-sink-tests/sources-and-sinks.cpp b/cpp/ql/test/library-tests/dataflow/source-sink-tests/sources-and-sinks.cpp
index c515a199f077..e4947a112f8d 100644
--- a/cpp/ql/test/library-tests/dataflow/source-sink-tests/sources-and-sinks.cpp
+++ b/cpp/ql/test/library-tests/dataflow/source-sink-tests/sources-and-sinks.cpp
@@ -115,3 +115,19 @@ void test_zmc(void *socket) {
// ...
}
}
+
+long StringCchGetsA(char *, size_t);
+long StringCchGetsExA(char *, size_t, char **, size_t *, unsigned long);
+
+void test_strsafe_gets() {
+ {
+ char dest[256] = {0};
+ StringCchGetsA(dest, sizeof(dest)); // $ local_source
+ }
+ {
+ char dest[256] = {0};
+ char *end;
+ size_t remaining;
+ StringCchGetsExA(dest, sizeof(dest), &end, &remaining, 0); // $ local_source
+ }
+}
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
index 0f4d67f2695f..9224cd62e82f 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected
@@ -8008,6 +8008,174 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
| taint.cpp:866:26:866:34 | ref arg & ... | taint.cpp:866:27:866:34 | size_out [inner post update] | |
| taint.cpp:866:27:866:34 | size_out | taint.cpp:866:26:866:34 | & ... | |
| taint.cpp:867:8:867:8 | p | taint.cpp:867:7:867:8 | * ... | TAINT |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:897:38:897:43 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:907:37:907:42 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:914:40:914:45 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:919:39:919:44 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:926:41:926:46 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:931:37:931:42 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:941:36:941:41 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:948:39:948:44 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:953:38:953:43 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:960:40:960:45 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:965:46:965:51 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:975:45:975:50 | source | |
+| taint.cpp:892:17:892:31 | call to indirect_source | taint.cpp:982:69:982:74 | source | |
+| taint.cpp:893:32:893:46 | call to indirect_source | taint.cpp:902:38:902:44 | wsource | |
+| taint.cpp:893:32:893:46 | call to indirect_source | taint.cpp:936:37:936:43 | wsource | |
+| taint.cpp:893:32:893:46 | call to indirect_source | taint.cpp:970:47:970:53 | wsource | |
+| taint.cpp:896:19:896:22 | {...} | taint.cpp:897:18:897:21 | dest | |
+| taint.cpp:896:19:896:22 | {...} | taint.cpp:897:31:897:34 | dest | |
+| taint.cpp:896:19:896:22 | {...} | taint.cpp:898:9:898:12 | dest | |
+| taint.cpp:896:21:896:21 | 0 | taint.cpp:896:19:896:22 | {...} | TAINT |
+| taint.cpp:897:18:897:21 | ref arg dest | taint.cpp:898:9:898:12 | dest | |
+| taint.cpp:898:9:898:12 | dest | taint.cpp:898:8:898:12 | * ... | |
+| taint.cpp:901:22:901:25 | {...} | taint.cpp:902:18:902:21 | dest | |
+| taint.cpp:901:22:901:25 | {...} | taint.cpp:902:31:902:34 | dest | |
+| taint.cpp:901:22:901:25 | {...} | taint.cpp:903:9:903:12 | dest | |
+| taint.cpp:901:24:901:24 | 0 | taint.cpp:901:22:901:25 | {...} | TAINT |
+| taint.cpp:902:18:902:21 | ref arg dest | taint.cpp:903:9:903:12 | dest | |
+| taint.cpp:903:9:903:12 | dest | taint.cpp:903:8:903:12 | * ... | |
+| taint.cpp:906:19:906:22 | {...} | taint.cpp:907:17:907:20 | dest | |
+| taint.cpp:906:19:906:22 | {...} | taint.cpp:907:30:907:33 | dest | |
+| taint.cpp:906:19:906:22 | {...} | taint.cpp:908:9:908:12 | dest | |
+| taint.cpp:906:21:906:21 | 0 | taint.cpp:906:19:906:22 | {...} | TAINT |
+| taint.cpp:907:17:907:20 | ref arg dest | taint.cpp:908:9:908:12 | dest | |
+| taint.cpp:908:9:908:12 | dest | taint.cpp:908:8:908:12 | * ... | |
+| taint.cpp:911:19:911:22 | {...} | taint.cpp:914:20:914:23 | dest | |
+| taint.cpp:911:19:911:22 | {...} | taint.cpp:914:33:914:36 | dest | |
+| taint.cpp:911:19:911:22 | {...} | taint.cpp:915:9:915:12 | dest | |
+| taint.cpp:911:21:911:21 | 0 | taint.cpp:911:19:911:22 | {...} | TAINT |
+| taint.cpp:912:9:912:11 | end | taint.cpp:914:49:914:51 | end | |
+| taint.cpp:913:10:913:18 | remaining | taint.cpp:914:55:914:63 | remaining | |
+| taint.cpp:914:20:914:23 | ref arg dest | taint.cpp:915:9:915:12 | dest | |
+| taint.cpp:914:48:914:51 | ref arg & ... | taint.cpp:914:49:914:51 | end [inner post update] | |
+| taint.cpp:914:49:914:51 | end | taint.cpp:914:48:914:51 | & ... | |
+| taint.cpp:914:54:914:63 | ref arg & ... | taint.cpp:914:55:914:63 | remaining [inner post update] | |
+| taint.cpp:914:55:914:63 | remaining | taint.cpp:914:54:914:63 | & ... | |
+| taint.cpp:915:9:915:12 | dest | taint.cpp:915:8:915:12 | * ... | |
+| taint.cpp:918:19:918:22 | {...} | taint.cpp:919:19:919:22 | dest | |
+| taint.cpp:918:19:918:22 | {...} | taint.cpp:919:32:919:35 | dest | |
+| taint.cpp:918:19:918:22 | {...} | taint.cpp:920:9:920:12 | dest | |
+| taint.cpp:918:21:918:21 | 0 | taint.cpp:918:19:918:22 | {...} | TAINT |
+| taint.cpp:919:19:919:22 | ref arg dest | taint.cpp:920:9:920:12 | dest | |
+| taint.cpp:920:9:920:12 | dest | taint.cpp:920:8:920:12 | * ... | |
+| taint.cpp:923:19:923:22 | {...} | taint.cpp:926:21:926:24 | dest | |
+| taint.cpp:923:19:923:22 | {...} | taint.cpp:926:34:926:37 | dest | |
+| taint.cpp:923:19:923:22 | {...} | taint.cpp:927:8:927:11 | dest | |
+| taint.cpp:923:21:923:21 | 0 | taint.cpp:923:19:923:22 | {...} | TAINT |
+| taint.cpp:924:9:924:11 | end | taint.cpp:926:55:926:57 | end | |
+| taint.cpp:925:10:925:18 | remaining | taint.cpp:926:61:926:69 | remaining | |
+| taint.cpp:926:21:926:24 | ref arg dest | taint.cpp:927:8:927:11 | dest | |
+| taint.cpp:926:54:926:57 | ref arg & ... | taint.cpp:926:55:926:57 | end [inner post update] | |
+| taint.cpp:926:55:926:57 | end | taint.cpp:926:54:926:57 | & ... | |
+| taint.cpp:926:60:926:69 | ref arg & ... | taint.cpp:926:61:926:69 | remaining [inner post update] | |
+| taint.cpp:926:61:926:69 | remaining | taint.cpp:926:60:926:69 | & ... | |
+| taint.cpp:930:20:930:27 | prefix | taint.cpp:931:17:931:20 | dest | |
+| taint.cpp:930:20:930:27 | prefix | taint.cpp:931:30:931:33 | dest | |
+| taint.cpp:930:20:930:27 | prefix | taint.cpp:932:9:932:12 | dest | |
+| taint.cpp:931:17:931:20 | ref arg dest | taint.cpp:932:9:932:12 | dest | |
+| taint.cpp:932:9:932:12 | dest | taint.cpp:932:8:932:12 | * ... | |
+| taint.cpp:935:23:935:31 | prefix | taint.cpp:936:17:936:20 | dest | |
+| taint.cpp:935:23:935:31 | prefix | taint.cpp:936:30:936:33 | dest | |
+| taint.cpp:935:23:935:31 | prefix | taint.cpp:937:9:937:12 | dest | |
+| taint.cpp:936:17:936:20 | ref arg dest | taint.cpp:937:9:937:12 | dest | |
+| taint.cpp:937:9:937:12 | dest | taint.cpp:937:8:937:12 | * ... | |
+| taint.cpp:940:20:940:27 | prefix | taint.cpp:941:16:941:19 | dest | |
+| taint.cpp:940:20:940:27 | prefix | taint.cpp:941:29:941:32 | dest | |
+| taint.cpp:940:20:940:27 | prefix | taint.cpp:942:9:942:12 | dest | |
+| taint.cpp:941:16:941:19 | ref arg dest | taint.cpp:942:9:942:12 | dest | |
+| taint.cpp:942:9:942:12 | dest | taint.cpp:942:8:942:12 | * ... | |
+| taint.cpp:945:20:945:27 | prefix | taint.cpp:948:19:948:22 | dest | |
+| taint.cpp:945:20:945:27 | prefix | taint.cpp:948:32:948:35 | dest | |
+| taint.cpp:945:20:945:27 | prefix | taint.cpp:949:9:949:12 | dest | |
+| taint.cpp:946:9:946:11 | end | taint.cpp:948:48:948:50 | end | |
+| taint.cpp:947:10:947:18 | remaining | taint.cpp:948:54:948:62 | remaining | |
+| taint.cpp:948:19:948:22 | ref arg dest | taint.cpp:949:9:949:12 | dest | |
+| taint.cpp:948:47:948:50 | ref arg & ... | taint.cpp:948:48:948:50 | end [inner post update] | |
+| taint.cpp:948:48:948:50 | end | taint.cpp:948:47:948:50 | & ... | |
+| taint.cpp:948:53:948:62 | ref arg & ... | taint.cpp:948:54:948:62 | remaining [inner post update] | |
+| taint.cpp:948:54:948:62 | remaining | taint.cpp:948:53:948:62 | & ... | |
+| taint.cpp:949:9:949:12 | dest | taint.cpp:949:8:949:12 | * ... | |
+| taint.cpp:952:20:952:27 | prefix | taint.cpp:953:18:953:21 | dest | |
+| taint.cpp:952:20:952:27 | prefix | taint.cpp:953:31:953:34 | dest | |
+| taint.cpp:952:20:952:27 | prefix | taint.cpp:954:9:954:12 | dest | |
+| taint.cpp:953:18:953:21 | ref arg dest | taint.cpp:954:9:954:12 | dest | |
+| taint.cpp:954:9:954:12 | dest | taint.cpp:954:8:954:12 | * ... | |
+| taint.cpp:957:20:957:27 | prefix | taint.cpp:960:20:960:23 | dest | |
+| taint.cpp:957:20:957:27 | prefix | taint.cpp:960:33:960:36 | dest | |
+| taint.cpp:957:20:957:27 | prefix | taint.cpp:961:9:961:12 | dest | |
+| taint.cpp:958:9:958:11 | end | taint.cpp:960:54:960:56 | end | |
+| taint.cpp:959:10:959:18 | remaining | taint.cpp:960:60:960:68 | remaining | |
+| taint.cpp:960:20:960:23 | ref arg dest | taint.cpp:961:9:961:12 | dest | |
+| taint.cpp:960:53:960:56 | ref arg & ... | taint.cpp:960:54:960:56 | end [inner post update] | |
+| taint.cpp:960:54:960:56 | end | taint.cpp:960:53:960:56 | & ... | |
+| taint.cpp:960:59:960:68 | ref arg & ... | taint.cpp:960:60:960:68 | remaining [inner post update] | |
+| taint.cpp:960:60:960:68 | remaining | taint.cpp:960:59:960:68 | & ... | |
+| taint.cpp:961:9:961:12 | dest | taint.cpp:961:8:961:12 | * ... | |
+| taint.cpp:964:19:964:22 | {...} | taint.cpp:965:20:965:23 | dest | |
+| taint.cpp:964:19:964:22 | {...} | taint.cpp:965:33:965:36 | dest | |
+| taint.cpp:964:19:964:22 | {...} | taint.cpp:966:9:966:12 | dest | |
+| taint.cpp:964:21:964:21 | 0 | taint.cpp:964:19:964:22 | {...} | TAINT |
+| taint.cpp:965:20:965:23 | ref arg dest | taint.cpp:966:9:966:12 | dest | |
+| taint.cpp:965:40:965:43 | %s | taint.cpp:965:20:965:23 | ref arg dest | TAINT |
+| taint.cpp:965:46:965:51 | ref arg source | taint.cpp:975:45:975:50 | source | |
+| taint.cpp:965:46:965:51 | ref arg source | taint.cpp:982:69:982:74 | source | |
+| taint.cpp:965:46:965:51 | source | taint.cpp:965:20:965:23 | ref arg dest | TAINT |
+| taint.cpp:966:9:966:12 | dest | taint.cpp:966:8:966:12 | * ... | |
+| taint.cpp:969:22:969:25 | {...} | taint.cpp:970:20:970:23 | dest | |
+| taint.cpp:969:22:969:25 | {...} | taint.cpp:970:33:970:36 | dest | |
+| taint.cpp:969:22:969:25 | {...} | taint.cpp:971:9:971:12 | dest | |
+| taint.cpp:969:24:969:24 | 0 | taint.cpp:969:22:969:25 | {...} | TAINT |
+| taint.cpp:970:20:970:23 | ref arg dest | taint.cpp:971:9:971:12 | dest | |
+| taint.cpp:970:40:970:44 | %s | taint.cpp:970:20:970:23 | ref arg dest | TAINT |
+| taint.cpp:970:47:970:53 | wsource | taint.cpp:970:20:970:23 | ref arg dest | TAINT |
+| taint.cpp:971:9:971:12 | dest | taint.cpp:971:8:971:12 | * ... | |
+| taint.cpp:974:19:974:22 | {...} | taint.cpp:975:19:975:22 | dest | |
+| taint.cpp:974:19:974:22 | {...} | taint.cpp:975:32:975:35 | dest | |
+| taint.cpp:974:19:974:22 | {...} | taint.cpp:976:9:976:12 | dest | |
+| taint.cpp:974:21:974:21 | 0 | taint.cpp:974:19:974:22 | {...} | TAINT |
+| taint.cpp:975:19:975:22 | ref arg dest | taint.cpp:976:9:976:12 | dest | |
+| taint.cpp:975:39:975:42 | %s | taint.cpp:975:19:975:22 | ref arg dest | TAINT |
+| taint.cpp:975:45:975:50 | ref arg source | taint.cpp:982:69:982:74 | source | |
+| taint.cpp:975:45:975:50 | source | taint.cpp:975:19:975:22 | ref arg dest | TAINT |
+| taint.cpp:976:9:976:12 | dest | taint.cpp:976:8:976:12 | * ... | |
+| taint.cpp:979:19:979:22 | {...} | taint.cpp:982:22:982:25 | dest | |
+| taint.cpp:979:19:979:22 | {...} | taint.cpp:982:35:982:38 | dest | |
+| taint.cpp:979:19:979:22 | {...} | taint.cpp:983:9:983:12 | dest | |
+| taint.cpp:979:21:979:21 | 0 | taint.cpp:979:19:979:22 | {...} | TAINT |
+| taint.cpp:980:9:980:11 | end | taint.cpp:982:43:982:45 | end | |
+| taint.cpp:981:10:981:18 | remaining | taint.cpp:982:49:982:57 | remaining | |
+| taint.cpp:982:22:982:25 | ref arg dest | taint.cpp:983:9:983:12 | dest | |
+| taint.cpp:982:42:982:45 | ref arg & ... | taint.cpp:982:43:982:45 | end [inner post update] | |
+| taint.cpp:982:43:982:45 | end | taint.cpp:982:42:982:45 | & ... | |
+| taint.cpp:982:48:982:57 | ref arg & ... | taint.cpp:982:49:982:57 | remaining [inner post update] | |
+| taint.cpp:982:49:982:57 | remaining | taint.cpp:982:48:982:57 | & ... | |
+| taint.cpp:982:63:982:66 | %s | taint.cpp:982:22:982:25 | ref arg dest | TAINT |
+| taint.cpp:982:69:982:74 | source | taint.cpp:982:22:982:25 | ref arg dest | TAINT |
+| taint.cpp:983:9:983:12 | dest | taint.cpp:983:8:983:12 | * ... | |
+| taint.cpp:986:19:986:22 | {...} | taint.cpp:988:20:988:23 | dest | |
+| taint.cpp:986:19:986:22 | {...} | taint.cpp:988:33:988:36 | dest | |
+| taint.cpp:986:19:986:22 | {...} | taint.cpp:989:9:989:12 | dest | |
+| taint.cpp:986:21:986:21 | 0 | taint.cpp:986:19:986:22 | {...} | TAINT |
+| taint.cpp:987:15:987:29 | call to indirect_source | taint.cpp:988:40:988:42 | fmt | |
+| taint.cpp:988:20:988:23 | ref arg dest | taint.cpp:989:9:989:12 | dest | |
+| taint.cpp:988:40:988:42 | fmt | taint.cpp:988:20:988:23 | ref arg dest | TAINT |
+| taint.cpp:989:9:989:12 | dest | taint.cpp:989:8:989:12 | * ... | |
+| taint.cpp:992:19:992:22 | {...} | taint.cpp:993:20:993:23 | dest | |
+| taint.cpp:992:19:992:22 | {...} | taint.cpp:993:33:993:36 | dest | |
+| taint.cpp:992:19:992:22 | {...} | taint.cpp:994:9:994:12 | dest | |
+| taint.cpp:992:21:992:21 | 0 | taint.cpp:992:19:992:22 | {...} | TAINT |
+| taint.cpp:993:20:993:23 | ref arg dest | taint.cpp:994:9:994:12 | dest | |
+| taint.cpp:993:40:993:43 | %d | taint.cpp:993:20:993:23 | ref arg dest | TAINT |
+| taint.cpp:993:46:993:47 | 42 | taint.cpp:993:20:993:23 | ref arg dest | TAINT |
+| taint.cpp:994:9:994:12 | dest | taint.cpp:994:8:994:12 | * ... | |
+| taint.cpp:997:19:997:22 | {...} | taint.cpp:998:18:998:21 | dest | |
+| taint.cpp:997:19:997:22 | {...} | taint.cpp:998:31:998:34 | dest | |
+| taint.cpp:997:19:997:22 | {...} | taint.cpp:999:9:999:12 | dest | |
+| taint.cpp:997:21:997:21 | 0 | taint.cpp:997:19:997:22 | {...} | TAINT |
+| taint.cpp:998:18:998:21 | ref arg dest | taint.cpp:999:9:999:12 | dest | |
+| taint.cpp:999:9:999:12 | dest | taint.cpp:999:8:999:12 | * ... | |
| thread.cpp:10:27:10:27 | s | thread.cpp:10:27:10:27 | s | |
| thread.cpp:10:27:10:27 | s | thread.cpp:11:8:11:8 | s | |
| thread.cpp:14:26:14:26 | s | thread.cpp:15:8:15:8 | s | |
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
index fa32e192239b..3168fb3a96f8 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
@@ -866,3 +866,136 @@ void test_iconv(size_t size) {
iconv(0, &s, &size, &p, &size_out);
sink(*p); // $ ast,ir
}
+
+using va_list = void*;
+
+long StringCchCopyA(char *, size_t, const char *);
+long StringCchCopyW(wchar_t *, size_t, const wchar_t *);
+long StringCbCopyA(char *, size_t, const char *);
+long StringCchCopyExA(char *, size_t, const char *, char **, size_t *, unsigned long);
+long StringCchCopyNA(char *, size_t, const char *, size_t);
+long StringCchCopyNExA(char *, size_t, const char *, size_t, char **, size_t *, unsigned long);
+long StringCchCatA(char *, size_t, const char *);
+long StringCchCatW(wchar_t *, size_t, const wchar_t *);
+long StringCbCatA(char *, size_t, const char *);
+long StringCchCatExA(char *, size_t, const char *, char **, size_t *, unsigned long);
+long StringCchCatNA(char *, size_t, const char *, size_t);
+long StringCchCatNExA(char *, size_t, const char *, size_t, char **, size_t *, unsigned long);
+long StringCchPrintfA(char *, size_t, const char *, ...);
+long StringCchPrintfW(wchar_t *, size_t, const wchar_t *, ...);
+long StringCbPrintfA(char *, size_t, const char *, ...);
+long StringCchPrintfExA(char *, size_t, char **, size_t *, unsigned long, const char *, ...);
+long StringCchVPrintfA(char *, size_t, const char *, va_list);
+long StringCchVPrintfExA(char *, size_t, char **, size_t *, unsigned long, const char *, va_list);
+
+void test_strsafe() {
+ char *source = indirect_source();
+ wchar_t *wsource = (wchar_t *)indirect_source();
+
+ {
+ char dest[256] = {0};
+ StringCchCopyA(dest, sizeof(dest), source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ wchar_t dest[256] = {0};
+ StringCchCopyW(dest, sizeof(dest), wsource);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ StringCbCopyA(dest, sizeof(dest), source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ char *end;
+ size_t remaining;
+ StringCchCopyExA(dest, sizeof(dest), source, &end, &remaining, 0);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ StringCchCopyNA(dest, sizeof(dest), source, 128);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ char *end;
+ size_t remaining;
+ StringCchCopyNExA(dest, sizeof(dest), source, 128, &end, &remaining, 0);
+ sink(dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = "prefix";
+ StringCchCatA(dest, sizeof(dest), source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ wchar_t dest[256] = L"prefix";
+ StringCchCatW(dest, sizeof(dest), wsource);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = "prefix";
+ StringCbCatA(dest, sizeof(dest), source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = "prefix";
+ char *end;
+ size_t remaining;
+ StringCchCatExA(dest, sizeof(dest), source, &end, &remaining, 0);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = "prefix";
+ StringCchCatNA(dest, sizeof(dest), source, 128);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = "prefix";
+ char *end;
+ size_t remaining;
+ StringCchCatNExA(dest, sizeof(dest), source, 128, &end, &remaining, 0);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ StringCchPrintfA(dest, sizeof(dest), "%s", source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ wchar_t dest[256] = {0};
+ StringCchPrintfW(dest, sizeof(dest), L"%s", wsource);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ StringCbPrintfA(dest, sizeof(dest), "%s", source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ char *end;
+ size_t remaining;
+ StringCchPrintfExA(dest, sizeof(dest), &end, &remaining, 0, "%s", source);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ char *fmt = indirect_source();
+ StringCchPrintfA(dest, sizeof(dest), fmt);
+ sink(*dest); // $ ir MISSING: ast
+ }
+ {
+ char dest[256] = {0};
+ StringCchPrintfA(dest, sizeof(dest), "%d", 42);
+ sink(*dest); // clean
+ }
+ {
+ char dest[256] = {0};
+ StringCchCopyA(dest, sizeof(dest), "hello");
+ sink(*dest); // clean
+ }
+}
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected
index e0002aa9c03f..5ad32759da58 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected
@@ -28044,6 +28044,118 @@ getParameterTypeName
| taint.cpp:859:8:859:12 | iconv | 4 | unsigned long * |
| taint.cpp:861:6:861:15 | test_iconv | 0 | size_t |
| taint.cpp:861:6:861:15 | test_iconv | 0 | unsigned long |
+| taint.cpp:872:6:872:19 | StringCchCopyA | 0 | char * |
+| taint.cpp:872:6:872:19 | StringCchCopyA | 1 | size_t |
+| taint.cpp:872:6:872:19 | StringCchCopyA | 1 | unsigned long |
+| taint.cpp:872:6:872:19 | StringCchCopyA | 2 | const char * |
+| taint.cpp:873:6:873:19 | StringCchCopyW | 0 | wchar_t * |
+| taint.cpp:873:6:873:19 | StringCchCopyW | 1 | size_t |
+| taint.cpp:873:6:873:19 | StringCchCopyW | 1 | unsigned long |
+| taint.cpp:873:6:873:19 | StringCchCopyW | 2 | const wchar_t * |
+| taint.cpp:874:6:874:18 | StringCbCopyA | 0 | char * |
+| taint.cpp:874:6:874:18 | StringCbCopyA | 1 | size_t |
+| taint.cpp:874:6:874:18 | StringCbCopyA | 1 | unsigned long |
+| taint.cpp:874:6:874:18 | StringCbCopyA | 2 | const char * |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 0 | char * |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 1 | size_t |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 1 | unsigned long |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 2 | const char * |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 3 | char ** |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 4 | size_t * |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 4 | unsigned long * |
+| taint.cpp:875:6:875:21 | StringCchCopyExA | 5 | unsigned long |
+| taint.cpp:876:6:876:20 | StringCchCopyNA | 0 | char * |
+| taint.cpp:876:6:876:20 | StringCchCopyNA | 1 | size_t |
+| taint.cpp:876:6:876:20 | StringCchCopyNA | 1 | unsigned long |
+| taint.cpp:876:6:876:20 | StringCchCopyNA | 2 | const char * |
+| taint.cpp:876:6:876:20 | StringCchCopyNA | 3 | size_t |
+| taint.cpp:876:6:876:20 | StringCchCopyNA | 3 | unsigned long |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 0 | char * |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 1 | size_t |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 1 | unsigned long |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 2 | const char * |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 3 | size_t |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 3 | unsigned long |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 4 | char ** |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 5 | size_t * |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 5 | unsigned long * |
+| taint.cpp:877:6:877:22 | StringCchCopyNExA | 6 | unsigned long |
+| taint.cpp:878:6:878:18 | StringCchCatA | 0 | char * |
+| taint.cpp:878:6:878:18 | StringCchCatA | 1 | size_t |
+| taint.cpp:878:6:878:18 | StringCchCatA | 1 | unsigned long |
+| taint.cpp:878:6:878:18 | StringCchCatA | 2 | const char * |
+| taint.cpp:879:6:879:18 | StringCchCatW | 0 | wchar_t * |
+| taint.cpp:879:6:879:18 | StringCchCatW | 1 | size_t |
+| taint.cpp:879:6:879:18 | StringCchCatW | 1 | unsigned long |
+| taint.cpp:879:6:879:18 | StringCchCatW | 2 | const wchar_t * |
+| taint.cpp:880:6:880:17 | StringCbCatA | 0 | char * |
+| taint.cpp:880:6:880:17 | StringCbCatA | 1 | size_t |
+| taint.cpp:880:6:880:17 | StringCbCatA | 1 | unsigned long |
+| taint.cpp:880:6:880:17 | StringCbCatA | 2 | const char * |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 0 | char * |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 1 | size_t |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 1 | unsigned long |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 2 | const char * |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 3 | char ** |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 4 | size_t * |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 4 | unsigned long * |
+| taint.cpp:881:6:881:20 | StringCchCatExA | 5 | unsigned long |
+| taint.cpp:882:6:882:19 | StringCchCatNA | 0 | char * |
+| taint.cpp:882:6:882:19 | StringCchCatNA | 1 | size_t |
+| taint.cpp:882:6:882:19 | StringCchCatNA | 1 | unsigned long |
+| taint.cpp:882:6:882:19 | StringCchCatNA | 2 | const char * |
+| taint.cpp:882:6:882:19 | StringCchCatNA | 3 | size_t |
+| taint.cpp:882:6:882:19 | StringCchCatNA | 3 | unsigned long |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 0 | char * |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 1 | size_t |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 1 | unsigned long |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 2 | const char * |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 3 | size_t |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 3 | unsigned long |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 4 | char ** |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 5 | size_t * |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 5 | unsigned long * |
+| taint.cpp:883:6:883:21 | StringCchCatNExA | 6 | unsigned long |
+| taint.cpp:884:6:884:21 | StringCchPrintfA | 0 | char * |
+| taint.cpp:884:6:884:21 | StringCchPrintfA | 1 | size_t |
+| taint.cpp:884:6:884:21 | StringCchPrintfA | 1 | unsigned long |
+| taint.cpp:884:6:884:21 | StringCchPrintfA | 2 | const char * |
+| taint.cpp:884:6:884:21 | StringCchPrintfA | 3 | ... |
+| taint.cpp:885:6:885:21 | StringCchPrintfW | 0 | wchar_t * |
+| taint.cpp:885:6:885:21 | StringCchPrintfW | 1 | size_t |
+| taint.cpp:885:6:885:21 | StringCchPrintfW | 1 | unsigned long |
+| taint.cpp:885:6:885:21 | StringCchPrintfW | 2 | const wchar_t * |
+| taint.cpp:885:6:885:21 | StringCchPrintfW | 3 | ... |
+| taint.cpp:886:6:886:20 | StringCbPrintfA | 0 | char * |
+| taint.cpp:886:6:886:20 | StringCbPrintfA | 1 | size_t |
+| taint.cpp:886:6:886:20 | StringCbPrintfA | 1 | unsigned long |
+| taint.cpp:886:6:886:20 | StringCbPrintfA | 2 | const char * |
+| taint.cpp:886:6:886:20 | StringCbPrintfA | 3 | ... |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 0 | char * |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 1 | size_t |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 1 | unsigned long |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 2 | char ** |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 3 | size_t * |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 3 | unsigned long * |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 4 | unsigned long |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 5 | const char * |
+| taint.cpp:887:6:887:23 | StringCchPrintfExA | 6 | ... |
+| taint.cpp:888:6:888:22 | StringCchVPrintfA | 0 | char * |
+| taint.cpp:888:6:888:22 | StringCchVPrintfA | 1 | size_t |
+| taint.cpp:888:6:888:22 | StringCchVPrintfA | 1 | unsigned long |
+| taint.cpp:888:6:888:22 | StringCchVPrintfA | 2 | const char * |
+| taint.cpp:888:6:888:22 | StringCchVPrintfA | 3 | va_list |
+| taint.cpp:888:6:888:22 | StringCchVPrintfA | 3 | void * |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 0 | char * |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 1 | size_t |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 1 | unsigned long |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 2 | char ** |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 3 | size_t * |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 3 | unsigned long * |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 4 | unsigned long |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 5 | const char * |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 6 | va_list |
+| taint.cpp:889:6:889:24 | StringCchVPrintfExA | 6 | void * |
| thread.cpp:4:6:4:9 | sink | 0 | int |
| thread.cpp:6:8:6:8 | operator= | 0 | S && |
| thread.cpp:6:8:6:8 | operator= | 0 | const S & |
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index c3e46114edf4..59b5f6214f3d 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -25796,9 +25796,9 @@ ir.cpp:
# 2919| getExpr(): [FunctionCall] call to VariableTemplateFunc
# 2919| Type = [DoubleType] double
# 2919| ValueCategory = prvalue
-# 2919| getArgument(0): [Literal] 2.299999999999999822
+# 2919| getArgument(0): [Literal] 2.3
# 2919| Type = [DoubleType] double
-# 2919| Value = [Literal] 2.299999999999999822
+# 2919| Value = [Literal] 2.3
# 2919| ValueCategory = prvalue
# 2919| getExpr().getFullyConverted(): [CStyleCast] (int)...
# 2919| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
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 66810913e5d3..96035c165331 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
@@ -12954,21 +12954,21 @@ ir.cpp:
# 1592| double StructuredBindingTupleRefGet::d
# 1592| Block 0
-# 1592| v1592_1(void) = EnterFunction :
-# 1592| m1592_2(unknown) = AliasedDefinition :
-# 1592| m1592_3(unknown) = InitializeNonLocal :
-# 1592| m1592_4(unknown) = Chi : total:m1592_2, partial:m1592_3
-# 1592| r1592_5(glval) = VariableAddress[#this] :
-# 1592| m1592_6(glval) = InitializeParameter[#this] : &:r1592_5
-# 1592| r1592_7(glval) = Load[#this] : &:r1592_5, m1592_6
-# 1592| m1592_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1592_7
-# 1592| r1592_9(glval) = FieldAddress[d] : r1592_7
-# 1592| r1592_10(double) = Constant[2.200000000000000178] :
-# 1592| m1592_11(double) = Store[?] : &:r1592_9, r1592_10
-# 1592| m1592_12(unknown) = Chi : total:m1592_8, partial:m1592_11
-# 1592| v1592_13(void) = ReturnVoid :
-# 1592| v1592_14(void) = AliasedUse : m1592_3
-# 1592| v1592_15(void) = ExitFunction :
+# 1592| v1592_1(void) = EnterFunction :
+# 1592| m1592_2(unknown) = AliasedDefinition :
+# 1592| m1592_3(unknown) = InitializeNonLocal :
+# 1592| m1592_4(unknown) = Chi : total:m1592_2, partial:m1592_3
+# 1592| r1592_5(glval) = VariableAddress[#this] :
+# 1592| m1592_6(glval) = InitializeParameter[#this] : &:r1592_5
+# 1592| r1592_7(glval) = Load[#this] : &:r1592_5, m1592_6
+# 1592| m1592_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1592_7
+# 1592| r1592_9(glval) = FieldAddress[d] : r1592_7
+# 1592| r1592_10(double) = Constant[2.2] :
+# 1592| m1592_11(double) = Store[?] : &:r1592_9, r1592_10
+# 1592| m1592_12(unknown) = Chi : total:m1592_8, partial:m1592_11
+# 1592| v1592_13(void) = ReturnVoid :
+# 1592| v1592_14(void) = AliasedUse : m1592_3
+# 1592| v1592_15(void) = ExitFunction :
# 1593| int& StructuredBindingTupleRefGet::r
# 1593| Block 0
@@ -21761,7 +21761,7 @@ ir.cpp:
# 2919| m2919_2(unknown) = AliasedDefinition :
# 2919| r2919_3(glval) = VariableAddress[VariableTemplateFuncUse] :
# 2919| r2919_4(glval) = FunctionAddress[VariableTemplateFunc] :
-# 2919| r2919_5(double) = Constant[2.299999999999999822] :
+# 2919| r2919_5(double) = Constant[2.3] :
# 2919| r2919_6(double) = Call[VariableTemplateFunc] : func:r2919_4, 0:r2919_5
# 2919| m2919_7(unknown) = ^CallSideEffect : ~m2919_2
# 2919| m2919_8(unknown) = Chi : total:m2919_2, partial:m2919_7
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 4e73b7d1aa6a..05ab6c50d703 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -11861,19 +11861,19 @@ ir.cpp:
# 1592| double StructuredBindingTupleRefGet::d
# 1592| Block 0
-# 1592| v1592_1(void) = EnterFunction :
-# 1592| mu1592_2(unknown) = AliasedDefinition :
-# 1592| mu1592_3(unknown) = InitializeNonLocal :
-# 1592| r1592_4(glval) = VariableAddress[#this] :
-# 1592| mu1592_5(glval) = InitializeParameter[#this] : &:r1592_4
-# 1592| r1592_6(glval) = Load[#this] : &:r1592_4, ~m?
-# 1592| mu1592_7(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1592_6
-# 1592| r1592_8(glval) = FieldAddress[d] : r1592_6
-# 1592| r1592_9(double) = Constant[2.200000000000000178] :
-# 1592| mu1592_10(double) = Store[?] : &:r1592_8, r1592_9
-# 1592| v1592_11(void) = ReturnVoid :
-# 1592| v1592_12(void) = AliasedUse : ~m?
-# 1592| v1592_13(void) = ExitFunction :
+# 1592| v1592_1(void) = EnterFunction :
+# 1592| mu1592_2(unknown) = AliasedDefinition :
+# 1592| mu1592_3(unknown) = InitializeNonLocal :
+# 1592| r1592_4(glval) = VariableAddress[#this] :
+# 1592| mu1592_5(glval) = InitializeParameter[#this] : &:r1592_4
+# 1592| r1592_6(glval) = Load[#this] : &:r1592_4, ~m?
+# 1592| mu1592_7(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1592_6
+# 1592| r1592_8(glval) = FieldAddress[d] : r1592_6
+# 1592| r1592_9(double) = Constant[2.2] :
+# 1592| mu1592_10(double) = Store[?] : &:r1592_8, r1592_9
+# 1592| v1592_11(void) = ReturnVoid :
+# 1592| v1592_12(void) = AliasedUse : ~m?
+# 1592| v1592_13(void) = ExitFunction :
# 1593| int& StructuredBindingTupleRefGet::r
# 1593| Block 0
@@ -19768,7 +19768,7 @@ ir.cpp:
# 2919| mu2919_2(unknown) = AliasedDefinition :
# 2919| r2919_3(glval) = VariableAddress[VariableTemplateFuncUse] :
# 2919| r2919_4(glval) = FunctionAddress[VariableTemplateFunc] :
-# 2919| r2919_5(double) = Constant[2.299999999999999822] :
+# 2919| r2919_5(double) = Constant[2.3] :
# 2919| r2919_6(double) = Call[VariableTemplateFunc] : func:r2919_4, 0:r2919_5
# 2919| mu2919_7(unknown) = ^CallSideEffect : ~m?
# 2919| r2919_8(int) = Convert : r2919_6
diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected
index b8424b8f01ad..7d441d6293a6 100644
--- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected
+++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected
@@ -1293,12 +1293,12 @@ estimateNrOfBounds
| test.c:415:26:415:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:415:30:415:30 | q | 1.0 | 1.0 | 1.0 |
| test.c:415:30:415:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:415:34:415:43 | 0.4743882700000000008 | 1.0 | -1.0 | -1.0 |
-| test.c:415:47:415:56 | 0.1433388700000000071 | 1.0 | -1.0 | -1.0 |
-| test.c:415:60:415:69 | 0.3527920299999999787 | 1.0 | -1.0 | -1.0 |
-| test.c:415:73:415:82 | 0.3920645799999999959 | 1.0 | -1.0 | -1.0 |
-| test.c:415:86:415:95 | 0.2154022499999999896 | 1.0 | -1.0 | -1.0 |
-| test.c:415:99:415:108 | 0.4049680500000000238 | 1.0 | -1.0 | -1.0 |
+| test.c:415:34:415:43 | 0.47438827 | 1.0 | -1.0 | -1.0 |
+| test.c:415:47:415:56 | 0.14333887 | 1.0 | -1.0 | -1.0 |
+| test.c:415:60:415:69 | 0.35279203 | 1.0 | -1.0 | -1.0 |
+| test.c:415:73:415:82 | 0.39206458 | 1.0 | -1.0 | -1.0 |
+| test.c:415:86:415:95 | 0.21540225 | 1.0 | -1.0 | -1.0 |
+| test.c:415:99:415:108 | 0.40496805 | 1.0 | -1.0 | -1.0 |
| test.c:416:14:416:14 | m | 2.0 | 1.0 | 1.0 |
| test.c:416:14:416:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:416:18:416:18 | n | 3.0 | 1.0 | 1.0 |
@@ -1309,12 +1309,12 @@ estimateNrOfBounds
| test.c:416:26:416:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:416:30:416:30 | q | 3.0 | 1.0 | 1.0 |
| test.c:416:30:416:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:416:34:416:43 | 0.3418334800000000229 | 1.0 | -1.0 | -1.0 |
-| test.c:416:47:416:56 | 0.3533464000000000049 | 1.0 | -1.0 | -1.0 |
-| test.c:416:60:416:69 | 0.2224785300000000077 | 1.0 | -1.0 | -1.0 |
-| test.c:416:73:416:82 | 0.326618929999999974 | 1.0 | -1.0 | -1.0 |
-| test.c:416:86:416:95 | 0.5927046500000000551 | 1.0 | -1.0 | -1.0 |
-| test.c:416:99:416:108 | 0.5297741000000000255 | 1.0 | -1.0 | -1.0 |
+| test.c:416:34:416:43 | 0.34183348 | 1.0 | -1.0 | -1.0 |
+| test.c:416:47:416:56 | 0.3533464 | 1.0 | -1.0 | -1.0 |
+| test.c:416:60:416:69 | 0.22247853 | 1.0 | -1.0 | -1.0 |
+| test.c:416:73:416:82 | 0.32661893 | 1.0 | -1.0 | -1.0 |
+| test.c:416:86:416:95 | 0.59270465 | 1.0 | -1.0 | -1.0 |
+| test.c:416:99:416:108 | 0.5297741 | 1.0 | -1.0 | -1.0 |
| test.c:417:14:417:14 | m | 3.5 | 1.0 | 1.0 |
| test.c:417:14:417:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:417:18:417:18 | n | 8.0 | 1.0 | 1.0 |
@@ -1325,12 +1325,12 @@ estimateNrOfBounds
| test.c:417:26:417:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:417:30:417:30 | q | 8.0 | 1.0 | 1.0 |
| test.c:417:30:417:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:417:34:417:43 | 0.774296030000000024 | 1.0 | -1.0 | -1.0 |
-| test.c:417:47:417:56 | 0.3147808400000000062 | 1.0 | -1.0 | -1.0 |
-| test.c:417:60:417:69 | 0.3123551399999999756 | 1.0 | -1.0 | -1.0 |
-| test.c:417:73:417:82 | 0.05121255999999999725 | 1.0 | -1.0 | -1.0 |
-| test.c:417:86:417:95 | 0.7931074500000000471 | 1.0 | -1.0 | -1.0 |
-| test.c:417:99:417:108 | 0.6798145100000000385 | 1.0 | -1.0 | -1.0 |
+| test.c:417:34:417:43 | 0.77429603 | 1.0 | -1.0 | -1.0 |
+| test.c:417:47:417:56 | 0.31478084 | 1.0 | -1.0 | -1.0 |
+| test.c:417:60:417:69 | 0.31235514 | 1.0 | -1.0 | -1.0 |
+| test.c:417:73:417:82 | 0.05121256 | 1.0 | -1.0 | -1.0 |
+| test.c:417:86:417:95 | 0.79310745 | 1.0 | -1.0 | -1.0 |
+| test.c:417:99:417:108 | 0.67981451 | 1.0 | -1.0 | -1.0 |
| test.c:418:14:418:14 | m | 5.75 | 1.0 | 1.0 |
| test.c:418:14:418:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:418:18:418:18 | n | 20.5 | 1.0 | 1.0 |
@@ -1341,12 +1341,12 @@ estimateNrOfBounds
| test.c:418:26:418:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:418:30:418:30 | q | 20.5 | 1.0 | 1.0 |
| test.c:418:30:418:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:418:34:418:43 | 0.4472955599999999809 | 1.0 | -1.0 | -1.0 |
-| test.c:418:47:418:56 | 0.8059920200000000312 | 1.0 | -1.0 | -1.0 |
-| test.c:418:60:418:69 | 0.9899726199999999698 | 1.0 | -1.0 | -1.0 |
-| test.c:418:73:418:82 | 0.5995273199999999747 | 1.0 | -1.0 | -1.0 |
-| test.c:418:86:418:95 | 0.3697694799999999837 | 1.0 | -1.0 | -1.0 |
-| test.c:418:99:418:108 | 0.8386683499999999514 | 1.0 | -1.0 | -1.0 |
+| test.c:418:34:418:43 | 0.44729556 | 1.0 | -1.0 | -1.0 |
+| test.c:418:47:418:56 | 0.80599202 | 1.0 | -1.0 | -1.0 |
+| test.c:418:60:418:69 | 0.98997262 | 1.0 | -1.0 | -1.0 |
+| test.c:418:73:418:82 | 0.59952732 | 1.0 | -1.0 | -1.0 |
+| test.c:418:86:418:95 | 0.36976948 | 1.0 | -1.0 | -1.0 |
+| test.c:418:99:418:108 | 0.83866835 | 1.0 | -1.0 | -1.0 |
| test.c:419:14:419:14 | m | 9.125 | 1.0 | 1.0 |
| test.c:419:14:419:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:419:18:419:18 | n | 51.75 | 1.0 | 1.0 |
@@ -1357,12 +1357,12 @@ estimateNrOfBounds
| test.c:419:26:419:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:419:30:419:30 | q | 51.75 | 1.0 | 1.0 |
| test.c:419:30:419:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:419:34:419:43 | 0.4931182800000000199 | 1.0 | -1.0 | -1.0 |
-| test.c:419:47:419:56 | 0.9038991100000000056 | 1.0 | -1.0 | -1.0 |
-| test.c:419:60:419:69 | 0.1059771199999999941 | 1.0 | -1.0 | -1.0 |
-| test.c:419:73:419:82 | 0.2177842600000000073 | 1.0 | -1.0 | -1.0 |
-| test.c:419:86:419:95 | 0.7248596600000000167 | 1.0 | -1.0 | -1.0 |
-| test.c:419:99:419:108 | 0.6873487400000000136 | 1.0 | -1.0 | -1.0 |
+| test.c:419:34:419:43 | 0.49311828 | 1.0 | -1.0 | -1.0 |
+| test.c:419:47:419:56 | 0.90389911 | 1.0 | -1.0 | -1.0 |
+| test.c:419:60:419:69 | 0.10597712 | 1.0 | -1.0 | -1.0 |
+| test.c:419:73:419:82 | 0.21778426 | 1.0 | -1.0 | -1.0 |
+| test.c:419:86:419:95 | 0.72485966 | 1.0 | -1.0 | -1.0 |
+| test.c:419:99:419:108 | 0.68734874 | 1.0 | -1.0 | -1.0 |
| test.c:420:14:420:14 | m | 14.1875 | 1.0 | 1.0 |
| test.c:420:14:420:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:420:18:420:18 | n | 129.875 | 1.0 | 1.0 |
@@ -1373,12 +1373,12 @@ estimateNrOfBounds
| test.c:420:26:420:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:420:30:420:30 | q | 129.875 | 1.0 | 1.0 |
| test.c:420:30:420:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:420:34:420:43 | 0.4745284799999999747 | 1.0 | -1.0 | -1.0 |
-| test.c:420:47:420:56 | 0.107866500000000004 | 1.0 | -1.0 | -1.0 |
-| test.c:420:60:420:69 | 0.1188457599999999947 | 1.0 | -1.0 | -1.0 |
-| test.c:420:73:420:82 | 0.7616405200000000431 | 1.0 | -1.0 | -1.0 |
-| test.c:420:86:420:95 | 0.3480889200000000239 | 1.0 | -1.0 | -1.0 |
-| test.c:420:99:420:108 | 0.584408649999999974 | 1.0 | -1.0 | -1.0 |
+| test.c:420:34:420:43 | 0.47452848 | 1.0 | -1.0 | -1.0 |
+| test.c:420:47:420:56 | 0.1078665 | 1.0 | -1.0 | -1.0 |
+| test.c:420:60:420:69 | 0.11884576 | 1.0 | -1.0 | -1.0 |
+| test.c:420:73:420:82 | 0.76164052 | 1.0 | -1.0 | -1.0 |
+| test.c:420:86:420:95 | 0.34808892 | 1.0 | -1.0 | -1.0 |
+| test.c:420:99:420:108 | 0.58440865 | 1.0 | -1.0 | -1.0 |
| test.c:421:14:421:14 | m | 21.78125 | 1.0 | 1.0 |
| test.c:421:14:421:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:421:18:421:18 | n | 325.1875 | 1.0 | 1.0 |
@@ -1390,11 +1390,11 @@ estimateNrOfBounds
| test.c:421:30:421:30 | q | 325.1875 | 1.0 | 1.0 |
| test.c:421:30:421:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:421:34:421:43 | 0.02524326 | 1.0 | -1.0 | -1.0 |
-| test.c:421:47:421:56 | 0.8290504600000000446 | 1.0 | -1.0 | -1.0 |
-| test.c:421:60:421:69 | 0.95823075000000002 | 1.0 | -1.0 | -1.0 |
-| test.c:421:73:421:82 | 0.1251655799999999985 | 1.0 | -1.0 | -1.0 |
-| test.c:421:86:421:95 | 0.8523517900000000536 | 1.0 | -1.0 | -1.0 |
-| test.c:421:99:421:108 | 0.3623238400000000081 | 1.0 | -1.0 | -1.0 |
+| test.c:421:47:421:56 | 0.82905046 | 1.0 | -1.0 | -1.0 |
+| test.c:421:60:421:69 | 0.95823075 | 1.0 | -1.0 | -1.0 |
+| test.c:421:73:421:82 | 0.12516558 | 1.0 | -1.0 | -1.0 |
+| test.c:421:86:421:95 | 0.85235179 | 1.0 | -1.0 | -1.0 |
+| test.c:421:99:421:108 | 0.36232384 | 1.0 | -1.0 | -1.0 |
| test.c:422:14:422:14 | m | 33.171875 | 1.0 | 1.0 |
| test.c:422:14:422:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:422:18:422:18 | n | 813.46875 | 1.0 | 1.0 |
@@ -1405,12 +1405,12 @@ estimateNrOfBounds
| test.c:422:26:422:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:422:30:422:30 | q | 813.46875 | 1.0 | 1.0 |
| test.c:422:30:422:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:422:34:422:43 | 0.3870862600000000153 | 1.0 | -1.0 | -1.0 |
-| test.c:422:47:422:56 | 0.3287604399999999871 | 1.0 | -1.0 | -1.0 |
-| test.c:422:60:422:69 | 0.1496348500000000137 | 1.0 | -1.0 | -1.0 |
-| test.c:422:73:422:82 | 0.4504110800000000192 | 1.0 | -1.0 | -1.0 |
-| test.c:422:86:422:95 | 0.4864090899999999884 | 1.0 | -1.0 | -1.0 |
-| test.c:422:99:422:108 | 0.8433127200000000157 | 1.0 | -1.0 | -1.0 |
+| test.c:422:34:422:43 | 0.38708626 | 1.0 | -1.0 | -1.0 |
+| test.c:422:47:422:56 | 0.32876044 | 1.0 | -1.0 | -1.0 |
+| test.c:422:60:422:69 | 0.14963485 | 1.0 | -1.0 | -1.0 |
+| test.c:422:73:422:82 | 0.45041108 | 1.0 | -1.0 | -1.0 |
+| test.c:422:86:422:95 | 0.48640909 | 1.0 | -1.0 | -1.0 |
+| test.c:422:99:422:108 | 0.84331272 | 1.0 | -1.0 | -1.0 |
| test.c:423:14:423:14 | m | 50.2578125 | 1.0 | 1.0 |
| test.c:423:14:423:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:423:18:423:18 | n | 2034.171875 | 1.0 | 1.0 |
@@ -1421,12 +1421,12 @@ estimateNrOfBounds
| test.c:423:26:423:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:423:30:423:30 | q | 2034.171875 | 1.0 | 1.0 |
| test.c:423:30:423:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:423:34:423:43 | 0.1575506299999999971 | 1.0 | -1.0 | -1.0 |
-| test.c:423:47:423:56 | 0.7708683299999999905 | 1.0 | -1.0 | -1.0 |
-| test.c:423:60:423:69 | 0.2642848099999999811 | 1.0 | -1.0 | -1.0 |
-| test.c:423:73:423:82 | 0.1480050800000000111 | 1.0 | -1.0 | -1.0 |
-| test.c:423:86:423:95 | 0.374281430000000026 | 1.0 | -1.0 | -1.0 |
-| test.c:423:99:423:108 | 0.05328182000000000057 | 1.0 | -1.0 | -1.0 |
+| test.c:423:34:423:43 | 0.15755063 | 1.0 | -1.0 | -1.0 |
+| test.c:423:47:423:56 | 0.77086833 | 1.0 | -1.0 | -1.0 |
+| test.c:423:60:423:69 | 0.26428481 | 1.0 | -1.0 | -1.0 |
+| test.c:423:73:423:82 | 0.14800508 | 1.0 | -1.0 | -1.0 |
+| test.c:423:86:423:95 | 0.37428143 | 1.0 | -1.0 | -1.0 |
+| test.c:423:99:423:108 | 0.05328182 | 1.0 | -1.0 | -1.0 |
| test.c:424:14:424:14 | m | 75.88671875 | 1.0 | 1.0 |
| test.c:424:14:424:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:424:18:424:18 | n | 5085.9296875 | 1.0 | 1.0 |
@@ -1437,12 +1437,12 @@ estimateNrOfBounds
| test.c:424:26:424:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:424:30:424:30 | q | 5085.9296875 | 1.0 | 1.0 |
| test.c:424:30:424:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:424:34:424:43 | 0.4173653600000000186 | 1.0 | -1.0 | -1.0 |
-| test.c:424:47:424:56 | 0.7682662799999999681 | 1.0 | -1.0 | -1.0 |
-| test.c:424:60:424:69 | 0.2764323799999999776 | 1.0 | -1.0 | -1.0 |
-| test.c:424:73:424:82 | 0.5567927400000000082 | 1.0 | -1.0 | -1.0 |
-| test.c:424:86:424:95 | 0.3946885700000000163 | 1.0 | -1.0 | -1.0 |
-| test.c:424:99:424:108 | 0.6907214400000000198 | 1.0 | -1.0 | -1.0 |
+| test.c:424:34:424:43 | 0.41736536 | 1.0 | -1.0 | -1.0 |
+| test.c:424:47:424:56 | 0.76826628 | 1.0 | -1.0 | -1.0 |
+| test.c:424:60:424:69 | 0.27643238 | 1.0 | -1.0 | -1.0 |
+| test.c:424:73:424:82 | 0.55679274 | 1.0 | -1.0 | -1.0 |
+| test.c:424:86:424:95 | 0.39468857 | 1.0 | -1.0 | -1.0 |
+| test.c:424:99:424:108 | 0.69072144 | 1.0 | -1.0 | -1.0 |
| test.c:425:14:425:14 | m | 114.330078125 | 1.0 | 1.0 |
| test.c:425:14:425:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:425:18:425:18 | n | 12715.32421875 | 1.0 | 1.0 |
@@ -1453,12 +1453,12 @@ estimateNrOfBounds
| test.c:425:26:425:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:425:30:425:30 | q | 12715.32421875 | 1.0 | 1.0 |
| test.c:425:30:425:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:425:34:425:43 | 0.8895534499999999678 | 1.0 | -1.0 | -1.0 |
-| test.c:425:47:425:56 | 0.2990482400000000207 | 1.0 | -1.0 | -1.0 |
-| test.c:425:60:425:69 | 0.7624258299999999711 | 1.0 | -1.0 | -1.0 |
-| test.c:425:73:425:82 | 0.2051910999999999874 | 1.0 | -1.0 | -1.0 |
-| test.c:425:86:425:95 | 0.8874555899999999609 | 1.0 | -1.0 | -1.0 |
-| test.c:425:99:425:108 | 0.8137279800000000174 | 1.0 | -1.0 | -1.0 |
+| test.c:425:34:425:43 | 0.88955345 | 1.0 | -1.0 | -1.0 |
+| test.c:425:47:425:56 | 0.29904824 | 1.0 | -1.0 | -1.0 |
+| test.c:425:60:425:69 | 0.76242583 | 1.0 | -1.0 | -1.0 |
+| test.c:425:73:425:82 | 0.2051911 | 1.0 | -1.0 | -1.0 |
+| test.c:425:86:425:95 | 0.88745559 | 1.0 | -1.0 | -1.0 |
+| test.c:425:99:425:108 | 0.81372798 | 1.0 | -1.0 | -1.0 |
| test.c:426:14:426:14 | m | 171.9951171875 | 1.0 | 1.0 |
| test.c:426:14:426:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:426:18:426:18 | n | 31788.810546875 | 1.0 | 1.0 |
@@ -1469,12 +1469,12 @@ estimateNrOfBounds
| test.c:426:26:426:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
| test.c:426:30:426:30 | q | 31788.810546875 | 1.0 | 1.0 |
| test.c:426:30:426:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 |
-| test.c:426:34:426:43 | 0.4218627600000000033 | 1.0 | -1.0 | -1.0 |
-| test.c:426:47:426:56 | 0.5384335799999999672 | 1.0 | -1.0 | -1.0 |
-| test.c:426:60:426:69 | 0.4499667900000000054 | 1.0 | -1.0 | -1.0 |
-| test.c:426:73:426:82 | 0.1320411400000000013 | 1.0 | -1.0 | -1.0 |
-| test.c:426:86:426:95 | 0.5203124099999999475 | 1.0 | -1.0 | -1.0 |
-| test.c:426:99:426:108 | 0.4276264699999999808 | 1.0 | -1.0 | -1.0 |
+| test.c:426:34:426:43 | 0.42186276 | 1.0 | -1.0 | -1.0 |
+| test.c:426:47:426:56 | 0.53843358 | 1.0 | -1.0 | -1.0 |
+| test.c:426:60:426:69 | 0.44996679 | 1.0 | -1.0 | -1.0 |
+| test.c:426:73:426:82 | 0.13204114 | 1.0 | -1.0 | -1.0 |
+| test.c:426:86:426:95 | 0.52031241 | 1.0 | -1.0 | -1.0 |
+| test.c:426:99:426:108 | 0.42762647 | 1.0 | -1.0 | -1.0 |
| test.c:432:19:432:19 | a | 1.0 | 1.0 | 1.0 |
| test.c:432:19:432:23 | ... + ... | 1.0 | 1.0 | 1.0 |
| test.c:432:19:432:27 | ... + ... | 1.0 | 1.0 | 1.0 |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/NonConstantFormat/NonConstantFormat.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/NonConstantFormat/NonConstantFormat.expected
index 9424c731765e..63851030bba5 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Format/NonConstantFormat/NonConstantFormat.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Format/NonConstantFormat/NonConstantFormat.expected
@@ -11,8 +11,13 @@ edges
| nested.cpp:86:19:86:46 | *call to __builtin_alloca | nested.cpp:87:18:87:20 | *fmt | provenance | |
| test.cpp:46:27:46:30 | **argv | test.cpp:130:20:130:26 | *access to array | provenance | |
| test.cpp:167:31:167:34 | *data | test.cpp:170:12:170:14 | *res | provenance | DataFlowFunction |
+| test.cpp:179:6:179:21 | [summary param] *2 in StringCchPrintfW | test.cpp:179:6:179:21 | [summary param] *0 in StringCchPrintfW [Return] | provenance | MaD:403 |
+| test.cpp:193:32:193:34 | *str | test.cpp:195:31:195:33 | *str | provenance | |
| test.cpp:193:32:193:34 | *str | test.cpp:195:31:195:33 | *str | provenance | |
| test.cpp:193:32:193:34 | *str | test.cpp:197:11:197:14 | *wstr | provenance | TaintFunction |
+| test.cpp:195:20:195:23 | StringCchPrintfW output argument | test.cpp:197:11:197:14 | *wstr | provenance | |
+| test.cpp:195:31:195:33 | *str | test.cpp:179:6:179:21 | [summary param] *2 in StringCchPrintfW | provenance | |
+| test.cpp:195:31:195:33 | *str | test.cpp:195:20:195:23 | StringCchPrintfW output argument | provenance | MaD:403 |
| test.cpp:204:25:204:36 | *call to get_string | test.cpp:204:25:204:36 | *call to get_string | provenance | |
| test.cpp:204:25:204:36 | *call to get_string | test.cpp:205:12:205:20 | *... + ... | provenance | |
| test.cpp:204:25:204:36 | *call to get_string | test.cpp:206:12:206:16 | *hello | provenance | |
@@ -55,7 +60,11 @@ nodes
| test.cpp:130:20:130:26 | *access to array | semmle.label | *access to array |
| test.cpp:167:31:167:34 | *data | semmle.label | *data |
| test.cpp:170:12:170:14 | *res | semmle.label | *res |
+| test.cpp:179:6:179:21 | [summary param] *0 in StringCchPrintfW [Return] | semmle.label | [summary param] *0 in StringCchPrintfW [Return] |
+| test.cpp:179:6:179:21 | [summary param] *2 in StringCchPrintfW | semmle.label | [summary param] *2 in StringCchPrintfW |
| test.cpp:193:32:193:34 | *str | semmle.label | *str |
+| test.cpp:195:20:195:23 | StringCchPrintfW output argument | semmle.label | StringCchPrintfW output argument |
+| test.cpp:195:31:195:33 | *str | semmle.label | *str |
| test.cpp:195:31:195:33 | *str | semmle.label | *str |
| test.cpp:197:11:197:14 | *wstr | semmle.label | *wstr |
| test.cpp:204:25:204:36 | *call to get_string | semmle.label | *call to get_string |
@@ -88,6 +97,7 @@ nodes
| test.cpp:245:25:245:36 | *call to get_string | semmle.label | *call to get_string |
| test.cpp:247:12:247:16 | *hello | semmle.label | *hello |
subpaths
+| test.cpp:195:31:195:33 | *str | test.cpp:179:6:179:21 | [summary param] *2 in StringCchPrintfW | test.cpp:179:6:179:21 | [summary param] *0 in StringCchPrintfW [Return] | test.cpp:195:20:195:23 | StringCchPrintfW output argument |
#select
| NonConstantFormat.c:30:10:30:16 | *access to array | NonConstantFormat.c:28:27:28:30 | **argv | NonConstantFormat.c:30:10:30:16 | *access to array | The format string argument to $@ has a source which cannot be verified to originate from a string literal. | NonConstantFormat.c:30:3:30:8 | call to printf | printf |
| NonConstantFormat.c:41:9:41:45 | *call to any_random_function | NonConstantFormat.c:41:9:41:45 | *call to any_random_function | NonConstantFormat.c:41:9:41:45 | *call to any_random_function | The format string argument to $@ has a source which cannot be verified to originate from a string literal. | NonConstantFormat.c:41:2:41:7 | call to printf | printf |
diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected
index d067430aba9c..162161e369b5 100644
--- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected
+++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected
@@ -2,10 +2,10 @@
| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:77:24:77:26 | (unnamed parameter 0) | int (unnamed parameter 0) |
| test.c:41:3:41:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:41:31:41:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:78:38:78:38 | x | int x |
| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:29:45:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:81:36:81:36 | x | int x |
-| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:37:45:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:81:50:81:50 | z | int z |
-| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x |
+| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:37:45:42 | 2.5E9 | 2.5E9 | file://:0:0:0:0 | float | float | test.c:81:50:81:50 | z | int z |
+| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3.5E15 | 3.5E15 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x |
| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y |
-| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x |
+| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3.5E15 | 3.5E15 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x |
| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y |
| test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a |
| test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:94:6:94:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a |
@@ -15,4 +15,4 @@
| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll |
| test.c:59:3:59:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:59:26:59:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll |
| test.c:61:3:61:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:100:8:100:26 | defined_with_double | defined_with_double | test.c:61:23:61:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:100:35:100:35 | d | double d |
-| test.c:62:3:62:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:62:26:62:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:104:44:104:45 | ll | long long ll |
+| test.c:62:3:62:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:62:26:62:31 | 3.5E15 | 3.5E15 | file://:0:0:0:0 | double | double | test.c:104:44:104:45 | ll | long long ll |
diff --git a/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme b/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme
new file mode 100644
index 000000000000..3cabc77473cb
--- /dev/null
+++ b/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme
@@ -0,0 +1,1505 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr
+ | @assign_op_call_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr | @parameter;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme b/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme
new file mode 100644
index 000000000000..ea7ad33252e5
--- /dev/null
+++ b/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme
@@ -0,0 +1,1505 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr
+ | @assign_op_call_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties b/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties
new file mode 100644
index 000000000000..72af45e177b8
--- /dev/null
+++ b/csharp/downgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties
@@ -0,0 +1,2 @@
+description: Remove `@parameter` from `@control_flow_element`
+compatibility: full
diff --git a/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/old.dbscheme b/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/old.dbscheme
new file mode 100644
index 000000000000..ea7ad33252e5
--- /dev/null
+++ b/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/old.dbscheme
@@ -0,0 +1,1505 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr
+ | @assign_op_call_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/semmlecode.csharp.dbscheme b/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/semmlecode.csharp.dbscheme
new file mode 100644
index 000000000000..19b8cc3e2dc7
--- /dev/null
+++ b/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/semmlecode.csharp.dbscheme
@@ -0,0 +1,1504 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/upgrade.properties b/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/upgrade.properties
new file mode 100644
index 000000000000..160cdb12de4c
--- /dev/null
+++ b/csharp/downgrades/ea7ad33252e550241975676f09fcc7b0a703deab/upgrade.properties
@@ -0,0 +1,2 @@
+description: Remove @assign_op_call_expr from @qualifiable_expr.
+compatibility: full
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs
index 9d3d79e4c4ff..699e06d273c8 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs
@@ -95,9 +95,9 @@ private string GetRestoreArgs(RestoreSettings restoreSettings)
args += " /p:EnableWindowsTargeting=true";
}
- if (restoreSettings.ExtraArgs is not null)
+ if (restoreSettings.NugetSources is not null)
{
- args += $" {restoreSettings.ExtraArgs}";
+ args += $" {restoreSettings.NugetSources}";
}
return args;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs
index eec6a2b8d3b2..d14dee506524 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs
@@ -17,7 +17,7 @@ public interface IDotNet
IList GetNugetFeedsFromFolder(string folderPath);
}
- public record class RestoreSettings(string File, string PackageDirectory, bool ForceDotnetRefAssemblyFetching, string? ExtraArgs = null, string? PathToNugetConfig = null, bool ForceReevaluation = false, bool TargetWindows = false);
+ public record class RestoreSettings(string File, string PackageDirectory, bool ForceDotnetRefAssemblyFetching, string? NugetSources = null, string? PathToNugetConfig = null, bool ForceReevaluation = false, bool TargetWindows = false);
public partial record class RestoreResult(bool Success, IList Output)
{
@@ -33,6 +33,9 @@ public partial record class RestoreResult(bool Success, IList Output)
private readonly Lazy hasNugetNoStablePackageVersionError = new(() => Output.Any(s => s.Contains("NU1103")));
public bool HasNugetNoStablePackageVersionError => hasNugetNoStablePackageVersionError.Value;
+ private readonly Lazy hasNugetPackageMissingError = new(() => Output.Any(s => s.Contains("NU1101")));
+ public bool HasNugetPackageMissingError => hasNugetPackageMissingError.Value;
+
private static IEnumerable GetFirstGroupOnMatch(Regex regex, IEnumerable lines) =>
lines
.Select(line => regex.Match(line))
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs
index b90b388e865c..e97b0b118c68 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs
@@ -33,7 +33,7 @@ internal class NugetExeWrapper : IDisposable
///
/// Create the package manager for a specified source tree.
///
- public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger)
+ public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func useDefaultFeed)
{
this.fileProvider = fileProvider;
this.packageDirectory = packageDirectory;
@@ -43,7 +43,7 @@ public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDir
{
logger.LogInfo($"Found packages.config files, trying to use nuget.exe for package restore");
nugetExe = ResolveNugetExe();
- if (HasNoPackageSource())
+ if (HasNoPackageSource() && useDefaultFeed())
{
// We only modify or add a top level nuget.config file
nugetConfigPath = Path.Combine(fileProvider.SourceDir.FullName, "nuget.config");
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs
index 1d01412ee051..e042285af11c 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Net;
@@ -27,8 +28,12 @@ internal sealed partial class NugetPackageRestorer : IDisposable
private readonly IDiagnosticsWriter diagnosticsWriter;
private readonly DependencyDirectory legacyPackageDirectory;
private readonly DependencyDirectory missingPackageDirectory;
+ private readonly DependencyDirectory emptyPackageDirectory;
private readonly ILogger logger;
private readonly ICompilationInfoContainer compilationInfoContainer;
+ private readonly bool checkNugetFeedResponsiveness = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
+ private readonly ImmutableHashSet privateRegistryFeeds;
+ private readonly bool hasPrivateRegistryFeeds;
public DependencyDirectory PackageDirectory { get; }
@@ -45,6 +50,8 @@ public NugetPackageRestorer(
this.fileContent = fileContent;
this.dotnet = dotnet;
this.dependabotProxy = dependabotProxy;
+ this.privateRegistryFeeds = dependabotProxy?.RegistryURLs.ToImmutableHashSet() ?? [];
+ this.hasPrivateRegistryFeeds = privateRegistryFeeds.Count > 0;
this.diagnosticsWriter = diagnosticsWriter;
this.logger = logger;
this.compilationInfoContainer = compilationInfoContainer;
@@ -52,6 +59,7 @@ public NugetPackageRestorer(
PackageDirectory = new DependencyDirectory("packages", "package", logger);
legacyPackageDirectory = new DependencyDirectory("legacypackages", "legacy package", logger);
missingPackageDirectory = new DependencyDirectory("missingpackages", "missing package", logger);
+ emptyPackageDirectory = new DependencyDirectory("empty", "empty package", logger);
}
public string? TryRestore(string package)
@@ -110,25 +118,50 @@ public DirectoryInfo[] GetOrderedPackageVersionSubDirectories(string packagePath
public HashSet Restore()
{
var assemblyLookupLocations = new HashSet();
- var checkNugetFeedResponsiveness = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
logger.LogInfo($"Checking NuGet feed responsiveness: {checkNugetFeedResponsiveness}");
compilationInfoContainer.CompilationInfos.Add(("NuGet feed responsiveness checked", checkNugetFeedResponsiveness ? "1" : "0"));
- HashSet? explicitFeeds = null;
- HashSet? allFeeds = null;
+ HashSet explicitFeeds = [];
+ HashSet reachableFeeds = [];
try
{
- if (checkNugetFeedResponsiveness && !CheckFeeds(out explicitFeeds, out allFeeds))
+ // Find feeds that are configured in NuGet.config files and divide them into ones that
+ // are explicitly configured for the project or by a private registry, and "all feeds"
+ // (including inherited ones) from other locations on the host outside of the working directory.
+ (explicitFeeds, var allFeeds) = GetAllFeeds();
+
+ if (checkNugetFeedResponsiveness)
{
- // todo: we could also check the reachability of the inherited nuget feeds, but to use those in the fallback we would need to handle authentication too.
- var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds([], explicitFeeds);
- return unresponsiveMissingPackageLocation is null
- ? []
- : [unresponsiveMissingPackageLocation];
+ var inheritedFeeds = allFeeds.Except(explicitFeeds).ToHashSet();
+
+ if (inheritedFeeds.Count > 0)
+ {
+ compilationInfoContainer.CompilationInfos.Add(("Inherited NuGet feed count", inheritedFeeds.Count.ToString()));
+ }
+
+ var timeout = CheckSpecifiedFeeds(explicitFeeds, out var reachableExplicitFeeds);
+ reachableFeeds.UnionWith(reachableExplicitFeeds);
+
+ var allExplicitReachable = explicitFeeds.Count == reachableExplicitFeeds.Count;
+ EmitUnreachableFeedsDiagnostics(allExplicitReachable);
+
+ if (timeout)
+ {
+ // If we experience a timeout, we use this fallback.
+ // todo: we could also check the reachability of the inherited nuget feeds, but to use those in the fallback we would need to handle authentication too.
+ var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds([], explicitFeeds);
+ return unresponsiveMissingPackageLocation is null
+ ? []
+ : [unresponsiveMissingPackageLocation];
+ }
+
+ // Inherited feeds should only be used, if they are indeed reachable (as they may be environment specific).
+ CheckSpecifiedFeeds(inheritedFeeds, out var reachableInheritedFeeds);
+ reachableFeeds.UnionWith(reachableInheritedFeeds);
}
- using (var nuget = new NugetExeWrapper(fileProvider, legacyPackageDirectory, logger))
+ using (var nuget = new NugetExeWrapper(fileProvider, legacyPackageDirectory, logger, IsDefaultFeedReachable))
{
var count = nuget.InstallPackages();
@@ -167,9 +200,10 @@ public HashSet Restore()
logger.LogError($"Failed to restore NuGet packages with nuget.exe: {exc.Message}");
}
- var restoredProjects = RestoreSolutions(out var container);
+ // Restore project dependencies with `dotnet restore`.
+ var restoredProjects = RestoreSolutions(reachableFeeds, out var container);
var projects = fileProvider.Projects.Except(restoredProjects);
- RestoreProjects(projects, allFeeds, out var containers);
+ RestoreProjects(projects, reachableFeeds, out var containers);
var dependencies = containers.Flatten(container);
@@ -192,6 +226,53 @@ public HashSet Restore()
return assemblyLookupLocations;
}
+ ///
+ /// Tests which of the feeds given by are reachable.
+ ///
+ /// The feeds to check.
+ /// Whether the feeds are fallback feeds or not.
+ /// Whether a timeout occurred while checking the feeds.
+ /// The list of feeds that could be reached.
+ private List GetReachableNuGetFeeds(HashSet feedsToCheck, bool isFallback, out bool isTimeout)
+ {
+ var fallbackStr = isFallback ? "fallback " : "";
+ logger.LogInfo($"Checking {fallbackStr}NuGet feed reachability on feeds: {string.Join(", ", feedsToCheck.OrderBy(f => f))}");
+
+ var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback);
+ var timeout = false;
+ var reachableFeeds = feedsToCheck
+ .Where(feed =>
+ {
+ var reachable = IsFeedReachable(feed, initialTimeout, tryCount, out var feedTimeout);
+ timeout |= feedTimeout;
+ return reachable;
+ })
+ .ToList();
+
+ if (reachableFeeds.Count == 0)
+ {
+ logger.LogWarning($"No {fallbackStr}NuGet feeds are reachable.");
+ }
+ else
+ {
+ logger.LogInfo($"Reachable {fallbackStr}NuGet feeds: {string.Join(", ", reachableFeeds.OrderBy(f => f))}");
+ }
+
+ isTimeout = timeout;
+ return reachableFeeds;
+ }
+
+ private bool IsDefaultFeedReachable()
+ {
+ if (checkNugetFeedResponsiveness)
+ {
+ var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: false);
+ return IsFeedReachable(PublicNugetOrgFeed, initialTimeout, tryCount, out var _);
+ }
+
+ return true;
+ }
+
private List GetReachableFallbackNugetFeeds(HashSet? feedsFromNugetConfigs)
{
var fallbackFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.FallbackNugetFeeds).ToHashSet();
@@ -212,17 +293,7 @@ private List GetReachableFallbackNugetFeeds(HashSet? feedsFromNu
}
}
- logger.LogInfo($"Checking fallback NuGet feed reachability on feeds: {string.Join(", ", fallbackFeeds.OrderBy(f => f))}");
- var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: true);
- var reachableFallbackFeeds = fallbackFeeds.Where(feed => IsFeedReachable(feed, initialTimeout, tryCount, allowExceptions: false)).ToList();
- if (reachableFallbackFeeds.Count == 0)
- {
- logger.LogWarning("No fallback NuGet feeds are reachable.");
- }
- else
- {
- logger.LogInfo($"Reachable fallback NuGet feeds: {string.Join(", ", reachableFallbackFeeds.OrderBy(f => f))}");
- }
+ var reachableFallbackFeeds = GetReachableNuGetFeeds(fallbackFeeds, isFallback: true, out var _);
compilationInfoContainer.CompilationInfos.Add(("Reachable fallback NuGet feed count", reachableFallbackFeeds.Count.ToString()));
@@ -237,10 +308,12 @@ private List GetReachableFallbackNugetFeeds(HashSet? feedsFromNu
/// Populates dependencies with the relevant dependencies from the assets files generated by the restore.
/// Returns a list of projects that are up to date with respect to restore.
///
- private IEnumerable RestoreSolutions(out DependencyContainer dependencies)
+ private IEnumerable RestoreSolutions(HashSet reachableFeeds, out DependencyContainer dependencies)
{
var successCount = 0;
var nugetSourceFailures = 0;
+ var nugetMissingPackageFailures = 0;
+
var assets = new Assets(logger);
var isWindows = fileContent.UseWindowsForms || fileContent.UseWpf;
@@ -248,7 +321,8 @@ private IEnumerable RestoreSolutions(out DependencyContainer dependencie
var projects = fileProvider.Solutions.SelectMany(solution =>
{
logger.LogInfo($"Restoring solution {solution}...");
- var res = dotnet.Restore(new(solution, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true, TargetWindows: isWindows));
+ var nugetSources = MakeRestoreSourcesArgument(solution, reachableFeeds);
+ var res = dotnet.Restore(new(solution, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true, NugetSources: nugetSources, TargetWindows: isWindows));
if (res.Success)
{
successCount++;
@@ -257,51 +331,84 @@ private IEnumerable RestoreSolutions(out DependencyContainer dependencie
{
nugetSourceFailures++;
}
+ if (res.HasNugetPackageMissingError)
+ {
+ nugetMissingPackageFailures++;
+ }
assets.AddDependenciesRange(res.AssetsFilePaths);
return res.RestoredProjects;
}).ToList();
dependencies = assets.Dependencies;
compilationInfoContainer.CompilationInfos.Add(("Successfully restored solution files", successCount.ToString()));
compilationInfoContainer.CompilationInfos.Add(("Failed solution restore with package source error", nugetSourceFailures.ToString()));
+ compilationInfoContainer.CompilationInfos.Add(("Failed solution restore with missing package error", nugetMissingPackageFailures.ToString()));
compilationInfoContainer.CompilationInfos.Add(("Restored projects through solution files", projects.Count.ToString()));
return projects;
}
+ private string FeedsToRestoreArgument(IEnumerable feeds)
+ {
+ // If there are no feeds, we want to override any default feeds that `dotnet restore` would use by passing a dummy source argument.
+ if (!feeds.Any())
+ {
+ return $" -s \"{emptyPackageDirectory.DirInfo.FullName}\"";
+ }
+
+ // Add package sources. If any are present, they override all sources specified in
+ // the configuration file(s).
+ var feedArgs = new StringBuilder();
+ foreach (var feed in feeds)
+ {
+ feedArgs.Append($" -s \"{feed}\"");
+ }
+
+ return feedArgs.ToString();
+ }
+
+ ///
+ /// Constructs the list of NuGet sources to use for this restore.
+ /// (1) Use the feeds we get from `dotnet nuget list source`
+ /// (2) Use private registries, if they are configured
+ ///
+ /// Path to project/solution
+ /// The set of reachable NuGet feeds.
+ /// A string representing the NuGet sources argument for the restore command.
+ private string? MakeRestoreSourcesArgument(string path, HashSet reachableFeeds)
+ {
+ // Do not construct an set of explicit NuGet sources to use for restore.
+ if (!checkNugetFeedResponsiveness && !hasPrivateRegistryFeeds)
+ {
+ return null;
+ }
+
+ // Find the path specific feeds.
+ var folder = GetDirectoryName(path);
+ var feedsToConsider = folder is not null ? GetFeeds(() => dotnet.GetNugetFeedsFromFolder(folder)).ToHashSet() : [];
+
+ if (hasPrivateRegistryFeeds)
+ {
+ feedsToConsider.UnionWith(privateRegistryFeeds);
+ }
+
+ var feedsToUse = checkNugetFeedResponsiveness
+ ? feedsToConsider.Where(reachableFeeds.Contains)
+ : feedsToConsider;
+
+ return FeedsToRestoreArgument(feedsToUse);
+ }
+
///
/// Executes `dotnet restore` on all projects in projects.
/// This is done in parallel for performance reasons.
/// Populates dependencies with the relative paths to the assets files generated by the restore.
///
/// A list of paths to project files.
- private void RestoreProjects(IEnumerable projects, HashSet? configuredSources, out ConcurrentBag dependencies)
- {
- // Conservatively, we only set this to a non-null value if a Dependabot proxy is enabled.
- // This ensures that we continue to get the old behaviour where feeds are taken from
- // `nuget.config` files instead of the command-line arguments.
- string? extraArgs = null;
-
- if (this.dependabotProxy is not null)
- {
- // If the Dependabot proxy is configured, then our main goal is to make `dotnet` aware
- // of the private registry feeds. However, since providing them as command-line arguments
- // to `dotnet` ignores other feeds that may be configured, we also need to add the feeds
- // we have discovered from analysing `nuget.config` files.
- var sources = configuredSources ?? new();
- this.dependabotProxy.RegistryURLs.ForEach(url => sources.Add(url));
-
- // Add package sources. If any are present, they override all sources specified in
- // the configuration file(s).
- var feedArgs = new StringBuilder();
- foreach (string source in sources)
- {
- feedArgs.Append($" -s {source}");
- }
-
- extraArgs = feedArgs.ToString();
- }
-
+ /// The set of reachable NuGet feeds.
+ private void RestoreProjects(IEnumerable projects, HashSet reachableFeeds, out ConcurrentBag dependencies)
+ {
var successCount = 0;
var nugetSourceFailures = 0;
+ var nugetMissingPackageFailures = 0;
ConcurrentBag collectedDependencies = [];
var isWindows = fileContent.UseWindowsForms || fileContent.UseWpf;
@@ -314,7 +421,8 @@ private void RestoreProjects(IEnumerable projects, HashSet? conf
foreach (var project in projectGroup)
{
logger.LogInfo($"Restoring project {project}...");
- var res = dotnet.Restore(new(project, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true, extraArgs, TargetWindows: isWindows));
+ var nugetSources = MakeRestoreSourcesArgument(project, reachableFeeds);
+ var res = dotnet.Restore(new(project, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true, NugetSources: nugetSources, TargetWindows: isWindows));
assets.AddDependenciesRange(res.AssetsFilePaths);
lock (sync)
{
@@ -326,6 +434,10 @@ private void RestoreProjects(IEnumerable projects, HashSet? conf
{
nugetSourceFailures++;
}
+ if (res.HasNugetPackageMissingError)
+ {
+ nugetMissingPackageFailures++;
+ }
}
}
collectedDependencies.Add(assets.Dependencies);
@@ -333,6 +445,7 @@ private void RestoreProjects(IEnumerable projects, HashSet? conf
dependencies = collectedDependencies;
compilationInfoContainer.CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
compilationInfoContainer.CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
+ compilationInfoContainer.CompilationInfos.Add(("Failed project restore with missing package error", nugetMissingPackageFailures.ToString()));
}
private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds(IEnumerable usedPackageNames, HashSet? feedsFromNugetConfigs)
@@ -623,28 +736,22 @@ private void TryChangeProjectFile(DirectoryInfo projectDir, Regex pattern, strin
}
}
- private static async Task ExecuteGetRequest(string address, HttpClient httpClient, CancellationToken cancellationToken)
+ private static async Task ExecuteGetRequest(string address, HttpClient httpClient, CancellationToken cancellationToken)
{
- using var stream = await httpClient.GetStreamAsync(address, cancellationToken);
- var buffer = new byte[1024];
- int bytesRead;
- while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
- {
- // do nothing
- }
+ return await httpClient.GetAsync(address, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
}
- private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount, bool allowExceptions = true)
+ private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount, out bool isTimeout)
{
logger.LogInfo($"Checking if NuGet feed '{feed}' is reachable...");
// Configure the HttpClient to be aware of the Dependabot Proxy, if used.
HttpClientHandler httpClientHandler = new();
- if (this.dependabotProxy != null)
+ if (dependabotProxy != null)
{
- httpClientHandler.Proxy = new WebProxy(this.dependabotProxy.Address);
+ httpClientHandler.Proxy = new WebProxy(dependabotProxy.Address);
- if (this.dependabotProxy.Certificate != null)
+ if (dependabotProxy.Certificate != null)
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) =>
{
@@ -659,7 +766,7 @@ private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount,
return false;
}
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
- chain.ChainPolicy.CustomTrustStore.Add(this.dependabotProxy.Certificate);
+ chain.ChainPolicy.CustomTrustStore.Add(dependabotProxy.Certificate);
return chain.Build(cert);
};
}
@@ -667,13 +774,17 @@ private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount,
using HttpClient client = new(httpClientHandler);
+ isTimeout = false;
+
for (var i = 0; i < tryCount; i++)
{
using var cts = new CancellationTokenSource();
cts.CancelAfter(timeoutMilliSeconds);
try
{
- ExecuteGetRequest(feed, client, cts.Token).GetAwaiter().GetResult();
+ logger.LogInfo($"Attempt {i + 1}/{tryCount} to reach NuGet feed '{feed}'.");
+ using var response = ExecuteGetRequest(feed, client, cts.Token).GetAwaiter().GetResult();
+ response.EnsureSuccessStatusCode();
logger.LogInfo($"Querying NuGet feed '{feed}' succeeded.");
return true;
}
@@ -688,14 +799,13 @@ private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount,
continue;
}
- // We're only interested in timeouts.
- var start = allowExceptions ? "Considering" : "Not considering";
- logger.LogInfo($"Querying NuGet feed '{feed}' failed in a timely manner. {start} the feed for use. The reason for the failure: {exc.Message}");
- return allowExceptions;
+ logger.LogInfo($"Querying NuGet feed '{feed}' failed. The reason for the failure: {exc.Message}");
+ return false;
}
}
logger.LogWarning($"Didn't receive answer from NuGet feed '{feed}'. Tried it {tryCount} times.");
+ isTimeout = true;
return false;
}
@@ -719,53 +829,61 @@ private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount,
}
///
- /// Checks that we can connect to all NuGet feeds that are explicitly configured in configuration files
- /// as well as any private package registry feeds that are configured.
+ /// Retrieves a list of excluded NuGet feeds from the corresponding environment variable.
///
- /// Outputs the set of explicit feeds.
- /// Outputs the set of all feeds (explicit and inherited).
- /// True if all feeds are reachable or false otherwise.
- private bool CheckFeeds(out HashSet explicitFeeds, out HashSet allFeeds)
+ private HashSet GetExcludedFeeds()
{
- (explicitFeeds, allFeeds) = GetAllFeeds();
- HashSet feedsToCheck = explicitFeeds;
-
- // If private package registries are configured for C#, then check those
- // in addition to the ones that are configured in `nuget.config` files.
- this.dependabotProxy?.RegistryURLs.ForEach(url => feedsToCheck.Add(url));
-
- var allFeedsReachable = this.CheckSpecifiedFeeds(feedsToCheck);
+ var excludedFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck)
+ .ToHashSet();
- var inheritedFeeds = allFeeds.Except(explicitFeeds).ToHashSet();
- if (inheritedFeeds.Count > 0)
+ if (excludedFeeds.Count > 0)
{
- logger.LogInfo($"Inherited NuGet feeds (not checked for reachability): {string.Join(", ", inheritedFeeds.OrderBy(f => f))}");
- compilationInfoContainer.CompilationInfos.Add(("Inherited NuGet feed count", inheritedFeeds.Count.ToString()));
+ logger.LogInfo($"Excluded NuGet feeds from responsiveness check: {string.Join(", ", excludedFeeds.OrderBy(f => f))}");
}
- return allFeedsReachable;
+ return excludedFeeds;
}
///
/// Checks that we can connect to the specified NuGet feeds.
///
/// The set of package feeds to check.
- /// True if all feeds are reachable or false otherwise.
- private bool CheckSpecifiedFeeds(HashSet feeds)
+ /// The list of feeds that were reachable.
+ ///
+ /// True if there is a timeout when trying to reach the feeds (excluding any feeds that are configured
+ /// to be excluded from the check) or false otherwise.
+ ///
+ private bool CheckSpecifiedFeeds(HashSet feeds, out HashSet reachableFeeds)
{
- logger.LogInfo("Checking that NuGet feeds are reachable...");
-
- var excludedFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck)
- .ToHashSet();
+ // Exclude any feeds from the feed check that are configured by the corresponding environment variable.
+ // These feeds are always assumed to be reachable.
+ var excludedFeeds = GetExcludedFeeds();
- if (excludedFeeds.Count > 0)
+ HashSet feedsToCheck = feeds.Where(feed =>
{
- logger.LogInfo($"Excluded NuGet feeds from responsiveness check: {string.Join(", ", excludedFeeds.OrderBy(f => f))}");
- }
+ if (excludedFeeds.Contains(feed))
+ {
+ logger.LogInfo($"Not checking reachability of NuGet feed '{feed}' as it is in the list of excluded feeds.");
+ return false;
+ }
+ return true;
+ }).ToHashSet();
+
+ reachableFeeds = GetReachableNuGetFeeds(feedsToCheck, isFallback: false, out var isTimeout).ToHashSet();
- var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: false);
+ // Always consider feeds excluded for the reachability check as reachable.
+ reachableFeeds.UnionWith(feeds.Where(feed => excludedFeeds.Contains(feed)));
- var allFeedsReachable = feeds.All(feed => excludedFeeds.Contains(feed) || IsFeedReachable(feed, initialTimeout, tryCount));
+ return isTimeout;
+ }
+
+ ///
+ /// If is `false`, logs this and emits a diagnostic.
+ /// Adds a `CompilationInfos` entry either way.
+ ///
+ /// Whether all feeds were reachable or not.
+ private void EmitUnreachableFeedsDiagnostics(bool allFeedsReachable)
+ {
if (!allFeedsReachable)
{
logger.LogWarning("Found unreachable NuGet feed in C# analysis with build-mode 'none'. This may cause missing dependencies in the analysis.");
@@ -779,8 +897,6 @@ private bool CheckSpecifiedFeeds(HashSet feeds)
));
}
compilationInfoContainer.CompilationInfos.Add(("All NuGet feeds reachable", allFeedsReachable ? "1" : "0"));
-
- return allFeedsReachable;
}
private IEnumerable GetFeeds(Func> getNugetFeeds)
@@ -811,6 +927,19 @@ private IEnumerable GetFeeds(Func> getNugetFeeds)
}
}
+ private string? GetDirectoryName(string path)
+ {
+ try
+ {
+ return new FileInfo(path).Directory?.FullName;
+ }
+ catch (Exception exc)
+ {
+ logger.LogWarning($"Failed to get directory of '{path}': {exc}");
+ }
+ return null;
+ }
+
private (HashSet explicitFeeds, HashSet allFeeds) GetAllFeeds()
{
var nugetConfigs = fileProvider.NugetConfigs;
@@ -828,11 +957,11 @@ private IEnumerable GetFeeds(Func> getNugetFeeds)
if (invalidNugetConfigs.Count() > 0)
{
- this.logger.LogWarning(string.Format(
+ logger.LogWarning(string.Format(
"Found incorrectly named NuGet configuration files: {0}",
string.Join(", ", invalidNugetConfigs)
));
- this.diagnosticsWriter.AddEntry(new DiagnosticMessage(
+ diagnosticsWriter.AddEntry(new DiagnosticMessage(
Language.CSharp,
"buildless/case-sensitive-nuget-config",
"Found NuGet configuration files which are not correctly named",
@@ -864,41 +993,33 @@ private IEnumerable GetFeeds(Func> getNugetFeeds)
logger.LogDebug("No NuGet feeds found in nuget.config files.");
}
- // todo: this could be improved.
- HashSet? allFeeds = null;
+ // If private package registries are configured for C#, then consider those
+ // in addition to the ones that are configured in `nuget.config` files.
+ if (hasPrivateRegistryFeeds)
+ {
+ logger.LogInfo($"Found {privateRegistryFeeds.Count} private registry feeds configured for C#: {string.Join(", ", privateRegistryFeeds.OrderBy(f => f))}");
+ explicitFeeds.UnionWith(privateRegistryFeeds);
+ }
+
+ HashSet allFeeds = [];
+
+ // Add all explicitFeeds to the set of all feeds.
+ allFeeds.UnionWith(explicitFeeds);
+
+ // Obtain the list of feeds from the root source directory.
+ // If a NuGet file is present it will be respected, otherwise we will just get the machine/environment specific feeds.
+ var nugetFeedsFromRoot = GetFeeds(() => dotnet.GetNugetFeedsFromFolder(fileProvider.SourceDir.FullName));
+ allFeeds.UnionWith(nugetFeedsFromRoot);
if (nugetConfigs.Count > 0)
{
- // We don't have to get the feeds from each of the folders from below, it would be enought to check the folders that recursively contain the others.
- allFeeds = nugetConfigs
- .Select(config =>
- {
- try
- {
- return new FileInfo(config).Directory?.FullName;
- }
- catch (Exception exc)
- {
- logger.LogWarning($"Failed to get directory of '{config}': {exc}");
- }
- return null;
- })
+ var nugetConfigFeeds = nugetConfigs
+ .Select(GetDirectoryName)
.Where(folder => folder != null)
.SelectMany(folder => GetFeeds(() => dotnet.GetNugetFeedsFromFolder(folder!)))
.ToHashSet();
- // If we have discovered any explicit feeds, then we also expect these to be in the set of all feeds.
- // Normally, it is a safe assumption to make that `GetNugetFeedsFromFolder` will include the feeds configured
- // in a NuGet configuration file in the given directory. There is one exception: on a system with case-sensitive
- // file systems, we may discover a configuration file such as `Nuget.Config` which is not recognised by `dotnet nuget`.
- // In that case, our call to `GetNugetFeeds` will retrieve the feeds from that file (because it is accepted when
- // provided explicitly as `--configfile` argument), but the call to `GetNugetFeedsFromFolder` will not.
- allFeeds.UnionWith(explicitFeeds);
- }
- else
- {
- // If we haven't found any `nuget.config` files, then obtain a list of feeds from the root source directory.
- allFeeds = GetFeeds(() => dotnet.GetNugetFeedsFromFolder(this.fileProvider.SourceDir.FullName)).ToHashSet();
+ allFeeds.UnionWith(nugetConfigFeeds);
}
logger.LogInfo($"Found {allFeeds.Count} NuGet feeds (with inherited ones) in nuget.config files: {string.Join(", ", allFeeds.OrderBy(f => f))}");
@@ -923,6 +1044,7 @@ public void Dispose()
PackageDirectory?.Dispose();
legacyPackageDirectory?.Dispose();
missingPackageDirectory?.Dispose();
+ emptyPackageDirectory?.Dispose();
}
///
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs
index 659b26c2fe99..92d7ecfad6bb 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
@@ -18,114 +20,68 @@ public static string GetName(this ISymbol symbol, bool useMetadataName = false)
return symbol.CanBeReferencedByName ? name : name.Substring(symbol.Name.LastIndexOf('.') + 1);
}
+ private static readonly ReadOnlyDictionary methodToOperator = new(new Dictionary
+ {
+ { "op_LogicalNot", "!" },
+ { "op_BitwiseAnd", "&" },
+ { "op_Equality", "==" },
+ { "op_Inequality", "!=" },
+ { "op_UnaryPlus", "+" },
+ { "op_Addition", "+" },
+ { "op_UnaryNegation", "-" },
+ { "op_Subtraction", "-" },
+ { "op_Multiply", "*" },
+ { "op_Multiplication", "*" },
+ { "op_Division", "/" },
+ { "op_Modulus", "%" },
+ { "op_GreaterThan", ">" },
+ { "op_GreaterThanOrEqual", ">=" },
+ { "op_LessThan", "<" },
+ { "op_LessThanOrEqual", "<=" },
+ { "op_Decrement", "--" },
+ { "op_Increment", "++" },
+ { "op_Implicit", "implicit conversion" },
+ { "op_Explicit", "explicit conversion" },
+ { "op_OnesComplement", "~" },
+ { "op_RightShift", ">>" },
+ { "op_UnsignedRightShift", ">>>" },
+ { "op_LeftShift", "<<" },
+ { "op_BitwiseOr", "|" },
+ { "op_ExclusiveOr", "^" },
+ { "op_True", "true" },
+ { "op_False", "false" }
+ });
+
///
/// Convert an operator method name in to a symbolic name.
/// A return value indicates whether the conversion succeeded.
///
public static bool TryGetOperatorSymbol(this ISymbol symbol, out string operatorName)
{
- static bool TryGetOperatorSymbolFromName(string methodName, out string operatorName)
+ var methodName = symbol.GetName(useMetadataName: false);
+
+ // Most common use-case.
+ if (methodToOperator.TryGetValue(methodName, out var opName))
{
- var success = true;
- switch (methodName)
- {
- case "op_LogicalNot":
- operatorName = "!";
- break;
- case "op_BitwiseAnd":
- operatorName = "&";
- break;
- case "op_Equality":
- operatorName = "==";
- break;
- case "op_Inequality":
- operatorName = "!=";
- break;
- case "op_UnaryPlus":
- case "op_Addition":
- operatorName = "+";
- break;
- case "op_UnaryNegation":
- case "op_Subtraction":
- operatorName = "-";
- break;
- case "op_Multiply":
- operatorName = "*";
- break;
- case "op_Division":
- operatorName = "/";
- break;
- case "op_Modulus":
- operatorName = "%";
- break;
- case "op_GreaterThan":
- operatorName = ">";
- break;
- case "op_GreaterThanOrEqual":
- operatorName = ">=";
- break;
- case "op_LessThan":
- operatorName = "<";
- break;
- case "op_LessThanOrEqual":
- operatorName = "<=";
- break;
- case "op_Decrement":
- operatorName = "--";
- break;
- case "op_Increment":
- operatorName = "++";
- break;
- case "op_Implicit":
- operatorName = "implicit conversion";
- break;
- case "op_Explicit":
- operatorName = "explicit conversion";
- break;
- case "op_OnesComplement":
- operatorName = "~";
- break;
- case "op_RightShift":
- operatorName = ">>";
- break;
- case "op_UnsignedRightShift":
- operatorName = ">>>";
- break;
- case "op_LeftShift":
- operatorName = "<<";
- break;
- case "op_BitwiseOr":
- operatorName = "|";
- break;
- case "op_ExclusiveOr":
- operatorName = "^";
- break;
- case "op_True":
- operatorName = "true";
- break;
- case "op_False":
- operatorName = "false";
- break;
- default:
- var match = CheckedRegex().Match(methodName);
- if (match.Success)
- {
- TryGetOperatorSymbolFromName($"op_{match.Groups[1]}", out var uncheckedName);
- operatorName = $"checked {uncheckedName}";
- break;
- }
- operatorName = methodName;
- success = false;
- break;
- }
- return success;
+ operatorName = opName;
+ return true;
}
- var methodName = symbol.GetName(useMetadataName: false);
- return TryGetOperatorSymbolFromName(methodName, out operatorName);
+ // Attempt to parse using a regexp.
+ var match = OperatorRegex().Match(methodName);
+ if (match.Success && methodToOperator.TryGetValue($"op_{match.Groups[2]}", out var rawOperatorName))
+ {
+ var prefix = match.Groups[1].Success ? "checked " : "";
+ var postfix = match.Groups[3].Success ? "=" : "";
+ operatorName = $"{prefix}{rawOperatorName}{postfix}";
+ return true;
+ }
+
+ operatorName = methodName;
+ return false;
}
- [GeneratedRegex("^op_Checked(.*)$")]
- private static partial Regex CheckedRegex();
+ [GeneratedRegex("^op_(Checked)?(.*?)(Assignment)?$")]
+ private static partial Regex OperatorRegex();
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
index 93107fc6dab8..4ab90def2c16 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
@@ -228,6 +228,41 @@ type.SpecialType is SpecialType.System_IntPtr ||
return Literal.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
}
+ ///
+ /// Given an expression syntax node, attempt to resolve the target method symbol for it.
+ /// The operation takes extension methods into account.
+ ///
+ /// The expression syntax node.
+ /// Returns the target method symbol, or null if it cannot be resolved.
+ protected IMethodSymbol? GetTargetSymbol(ExpressionSyntax node)
+ {
+ var si = Context.GetSymbolInfo(node);
+ if (si.Symbol is ISymbol symbol)
+ {
+ var method = symbol as IMethodSymbol;
+ // Case for compiler-generated extension methods.
+ return method?.TryGetExtensionMethod() ?? method;
+ }
+
+ if (si.CandidateReason == CandidateReason.OverloadResolutionFailure && node is InvocationExpressionSyntax syntax)
+ {
+ // This seems to be a bug in Roslyn
+ // For some reason, typeof(X).InvokeMember(...) fails to resolve the correct
+ // InvokeMember() method, even though the number of parameters clearly identifies the correct method
+
+ var candidates = si.CandidateSymbols
+ .OfType()
+ .Where(method => method.Parameters.Length >= syntax.ArgumentList.Arguments.Count)
+ .Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= syntax.ArgumentList.Arguments.Count);
+
+ return Context.ExtractionContext.IsStandalone ?
+ candidates.FirstOrDefault() :
+ candidates.SingleOrDefault();
+ }
+
+ return si.Symbol as IMethodSymbol;
+ }
+
///
/// Adapt the operator kind depending on whether it's a dynamic call or a user-operator call.
///
@@ -244,10 +279,10 @@ public static ExprKind UnaryOperatorKind(Context cx, ExprKind originalKind, Expr
/// name if available.
///
/// The expression.
- public void OperatorCall(TextWriter trapFile, ExpressionSyntax node)
+ public void AddOperatorCall(TextWriter trapFile, ExpressionSyntax node)
{
- var @operator = Context.GetSymbolInfo(node);
- if (@operator.Symbol is IMethodSymbol method)
+ var @operator = GetTargetSymbol(node);
+ if (@operator is IMethodSymbol method)
{
var callType = GetCallType(Context, node);
if (callType == CallType.Dynamic)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
index 67e49b2919c2..6d869b256c58 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
@@ -24,10 +24,9 @@ protected override void PopulateExpression(TextWriter trapFile)
{
Create(Context, Syntax.Left, this, 0);
Create(Context, Syntax.Right, this, 1);
-
if (Kind != ExprKind.SIMPLE_ASSIGN && Kind != ExprKind.ASSIGN_COALESCE)
{
- OperatorCall(trapFile, Syntax);
+ AddOperatorCall(trapFile, Syntax);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs
index d4cc5cc81d58..2bc8c61f21f3 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs
@@ -40,7 +40,7 @@ private void CreateDeferred(Context cx, ExpressionSyntax node, int child)
protected override void PopulateExpression(TextWriter trapFile)
{
- OperatorCall(trapFile, Syntax);
+ AddOperatorCall(trapFile, Syntax);
CreateDeferred(Context, Syntax.Left, 0);
CreateDeferred(Context, Syntax.Right, 1);
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs
index 20a5dc611a31..c11711f30926 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs
@@ -25,7 +25,7 @@ protected override void PopulateExpression(TextWriter trapFile)
else
{
// Type conversion
- OperatorCall(trapFile, Syntax);
+ AddOperatorCall(trapFile, Syntax);
TypeMention.Create(Context, Syntax.Type, this, Type);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs
index 2ed7aec9955c..343f288eeafe 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs
@@ -44,7 +44,7 @@ protected override void PopulateExpression(TextWriter trapFile)
var child = -1;
string? memberName = null;
- var target = TargetSymbol;
+ var target = GetTargetSymbol(Syntax);
switch (Syntax.Expression)
{
case MemberAccessExpressionSyntax memberAccess when IsValidMemberAccessKind():
@@ -129,39 +129,6 @@ private static bool IsOperatorLikeCall(ExpressionNodeInfo info)
method.TryGetExtensionMethod()?.MethodKind == MethodKind.UserDefinedOperator;
}
- public IMethodSymbol? TargetSymbol
- {
- get
- {
- var si = SymbolInfo;
-
- if (si.Symbol is ISymbol symbol)
- {
- var method = symbol as IMethodSymbol;
- // Case for compiler-generated extension methods.
- return method?.TryGetExtensionMethod() ?? method;
- }
-
- if (si.CandidateReason == CandidateReason.OverloadResolutionFailure)
- {
- // This seems to be a bug in Roslyn
- // For some reason, typeof(X).InvokeMember(...) fails to resolve the correct
- // InvokeMember() method, even though the number of parameters clearly identifies the correct method
-
- var candidates = si.CandidateSymbols
- .OfType()
- .Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count)
- .Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count);
-
- return Context.ExtractionContext.IsStandalone ?
- candidates.FirstOrDefault() :
- candidates.SingleOrDefault();
- }
-
- return si.Symbol as IMethodSymbol;
- }
- }
-
private static bool IsDelegateLikeCall(ExpressionNodeInfo info)
{
return IsDelegateLikeCall(info, symbol => IsFunctionPointer(symbol) || IsDelegateInvoke(symbol));
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs
index dbe5ecb3d184..051a03e9f8c2 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs
@@ -25,7 +25,7 @@ protected override void PopulateExpression(TextWriter trapFile)
if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) &&
Kind == ExprKind.OPERATOR_INVOCATION)
{
- OperatorCall(trapFile, Syntax);
+ AddOperatorCall(trapFile, Syntax);
trapFile.mutator_invocation_mode(this, 2);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs
index 161fbe62e3f1..699c3810d116 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs
@@ -24,7 +24,7 @@ public static Unary Create(ExpressionNodeInfo info)
protected override void PopulateExpression(TextWriter trapFile)
{
Create(Context, Syntax.Operand, this, 0);
- OperatorCall(trapFile, Syntax);
+ AddOperatorCall(trapFile, Syntax);
if ((operatorKind == ExprKind.PRE_INCR || operatorKind == ExprKind.PRE_DECR) &&
Kind == ExprKind.OPERATOR_INVOCATION)
diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
index 166a94bd88df..4cb7b5569687 100644
--- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.66
+
+No user-facing changes.
+
## 1.7.65
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.66.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.66.md
new file mode 100644
index 000000000000..7fc1a46a66ef
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.66.md
@@ -0,0 +1,3 @@
+## 1.7.66
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
index bf581427d298..7d0a2c0bc078 100644
--- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.65
+lastReleaseVersion: 1.7.66
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index 9d0e0ffd4f96..c5cfa0dcd89b 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.66-dev
+version: 1.7.67-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
index 166a94bd88df..4cb7b5569687 100644
--- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.66
+
+No user-facing changes.
+
## 1.7.65
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.66.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.66.md
new file mode 100644
index 000000000000..7fc1a46a66ef
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.66.md
@@ -0,0 +1,3 @@
+## 1.7.66
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
index bf581427d298..7d0a2c0bc078 100644
--- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.65
+lastReleaseVersion: 1.7.66
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index f5203f4e4434..c9f0acac983d 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.66-dev
+version: 1.7.67-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/consistency-queries/SsaConsistency.ql b/csharp/ql/consistency-queries/SsaConsistency.ql
index e9c9191b63a1..003e7ddd5e94 100644
--- a/csharp/ql/consistency-queries/SsaConsistency.ql
+++ b/csharp/ql/consistency-queries/SsaConsistency.ql
@@ -7,8 +7,8 @@ query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
// Local variables in C# must be initialized before every use, so uninitialized
// local variables should not have an SSA definition, as that would imply that
// the declaration is live (can reach a use without passing through a definition)
- exists(ExplicitDefinition def |
- d = def.getADefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
+ exists(SsaExplicitWrite def |
+ d = def.getDefinition().(AssignableDefinitions::LocalVariableDefinition).getDeclaration()
|
not d = any(ForeachStmt fs).getVariableDeclExpr() and
not d = any(SpecificCatchClause scc).getVariableDeclExpr() and
diff --git a/csharp/ql/integration-tests/all-platforms/standalone_resx/CompilationInfo.expected b/csharp/ql/integration-tests/all-platforms/standalone_resx/CompilationInfo.expected
index dfab1016a6b2..6d91b2700226 100644
--- a/csharp/ql/integration-tests/all-platforms/standalone_resx/CompilationInfo.expected
+++ b/csharp/ql/integration-tests/all-platforms/standalone_resx/CompilationInfo.expected
@@ -1,5 +1,7 @@
| All NuGet feeds reachable | 1.0 |
+| Failed project restore with missing package error | 0.0 |
| Failed project restore with package source error | 0.0 |
+| Failed solution restore with missing package error | 0.0 |
| Failed solution restore with package source error | 0.0 |
| Inherited NuGet feed count | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
diff --git a/csharp/ql/integration-tests/all-platforms/standalone_slnx/CompilationInfo.expected b/csharp/ql/integration-tests/all-platforms/standalone_slnx/CompilationInfo.expected
index 3bd3941b27c5..82cf0509d345 100644
--- a/csharp/ql/integration-tests/all-platforms/standalone_slnx/CompilationInfo.expected
+++ b/csharp/ql/integration-tests/all-platforms/standalone_slnx/CompilationInfo.expected
@@ -1,5 +1,7 @@
| All NuGet feeds reachable | 1.0 |
+| Failed project restore with missing package error | 0.0 |
| Failed project restore with package source error | 0.0 |
+| Failed solution restore with missing package error | 0.0 |
| Failed solution restore with package source error | 0.0 |
| Inherited NuGet feed count | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
diff --git a/csharp/ql/integration-tests/all-platforms/standalone_winforms/CompilationInfo.expected b/csharp/ql/integration-tests/all-platforms/standalone_winforms/CompilationInfo.expected
index 6b06566033c3..63ddd4903f3e 100644
--- a/csharp/ql/integration-tests/all-platforms/standalone_winforms/CompilationInfo.expected
+++ b/csharp/ql/integration-tests/all-platforms/standalone_winforms/CompilationInfo.expected
@@ -1,5 +1,7 @@
| All NuGet feeds reachable | 1.0 |
+| Failed project restore with missing package error | 0.0 |
| Failed project restore with package source error | 0.0 |
+| Failed solution restore with missing package error | 0.0 |
| Failed solution restore with package source error | 0.0 |
| Inherited NuGet feed count | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/Assemblies.expected b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/Assemblies.expected
new file mode 100644
index 000000000000..b676e41c1840
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/Assemblies.expected
@@ -0,0 +1 @@
+| test-db/working/packages/newtonsoft.json/13.0.4/lib/net6.0/Newtonsoft.Json.dll:0:0:0:0 | Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed |
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/Assemblies.ql b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/Assemblies.ql
new file mode 100644
index 000000000000..0eb33b7ae37b
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/Assemblies.ql
@@ -0,0 +1,5 @@
+import csharp
+
+from Assembly a
+where exists(a.getFile().getAbsolutePath().indexOf("newtonsoft.json"))
+select a
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/CompilationInfo.expected b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/CompilationInfo.expected
new file mode 100644
index 000000000000..ff0b29da33fa
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/CompilationInfo.expected
@@ -0,0 +1,22 @@
+| All NuGet feeds reachable | 1.0 |
+| Failed project restore with missing package error | 0.0 |
+| Failed project restore with package source error | 0.0 |
+| Failed solution restore with missing package error | 0.0 |
+| Failed solution restore with package source error | 0.0 |
+| Inherited NuGet feed count | 1.0 |
+| NuGet feed responsiveness checked | 1.0 |
+| Project files on filesystem | 1.0 |
+| Reachable fallback NuGet feed count | 1.0 |
+| Resolved assembly conflicts | 0.0 |
+| Resource extraction enabled | 0.0 |
+| Restored .NET framework variants | 1.0 |
+| Restored projects through solution files | 0.0 |
+| Solution files on filesystem | 0.0 |
+| Source files generated | 0.0 |
+| Source files on filesystem | 1.0 |
+| Successfully restored project files | 1.0 |
+| Successfully restored solution files | 0.0 |
+| Unresolved references | 0.0 |
+| UseWPF set | 0.0 |
+| UseWindowsForms set | 0.0 |
+| WebView extraction enabled | 1.0 |
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/CompilationInfo.ql b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/CompilationInfo.ql
new file mode 100644
index 000000000000..073ffe3b224d
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/CompilationInfo.ql
@@ -0,0 +1,15 @@
+import csharp
+import semmle.code.csharp.commons.Diagnostics
+
+query predicate compilationInfo(string key, float value) {
+ key != "Resolved references" and
+ not key.matches("Compiler diagnostic count for%") and
+ exists(Compilation c, string infoKey, string infoValue | infoValue = c.getInfo(infoKey) |
+ key = infoKey and
+ value = infoValue.toFloat()
+ or
+ not exists(infoValue.toFloat()) and
+ key = infoKey + ": " + infoValue and
+ value = 1
+ )
+}
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/clear/nuget.config b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/clear/nuget.config
new file mode 100644
index 000000000000..a3f3aea61c8f
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/clear/nuget.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/global.json b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/global.json
new file mode 100644
index 000000000000..ed6049740701
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/global.json
@@ -0,0 +1,5 @@
+{
+ "sdk": {
+ "version": "10.0.201"
+ }
+}
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/proj/Program.cs b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/proj/Program.cs
new file mode 100644
index 000000000000..c340f4c32fd4
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/proj/Program.cs
@@ -0,0 +1 @@
+class Program { }
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/proj/proj.csproj b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/proj/proj.csproj
new file mode 100644
index 000000000000..6010c6c7f37c
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/proj/proj.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net10.0
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/test.py b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/test.py
new file mode 100644
index 000000000000..cbbf2eb1d647
--- /dev/null
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_clear/test.py
@@ -0,0 +1,12 @@
+import os
+import runs_on
+
+
+@runs_on.posix
+def test(codeql, csharp):
+ # Making sure the reachability test of `nuget.org` succeeds:
+ os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_TIMEOUT"] = "1000"
+ os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_LIMIT"] = "5"
+
+ # This test checks that the nuget.config file in the clear folder is not applied to the restore of the project.
+ codeql.database.create(build_mode="none")
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_error/CompilationInfo.expected b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_error/CompilationInfo.expected
index 3a74bcbd56ed..4acd4f54e8a6 100644
--- a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_error/CompilationInfo.expected
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_error/CompilationInfo.expected
@@ -1,7 +1,10 @@
-| All NuGet feeds reachable | 1.0 |
-| Failed project restore with package source error | 1.0 |
+| All NuGet feeds reachable | 0.0 |
+| Failed project restore with missing package error | 1.0 |
+| Failed project restore with package source error | 0.0 |
+| Failed solution restore with missing package error | 0.0 |
| Failed solution restore with package source error | 0.0 |
| Fallback nuget restore | 1.0 |
+| Inherited NuGet feed count | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
| Project files on filesystem | 1.0 |
| Reachable fallback NuGet feed count | 1.0 |
diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_fallback/CompilationInfo.expected b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_fallback/CompilationInfo.expected
index c53a17f0300d..9cc03f2f5372 100644
--- a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_fallback/CompilationInfo.expected
+++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_config_fallback/CompilationInfo.expected
@@ -1,5 +1,6 @@
| All NuGet feeds reachable | 0.0 |
| Fallback nuget restore | 1.0 |
+| Inherited NuGet feed count | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
| Project files on filesystem | 1.0 |
| Reachable fallback NuGet feed count | 2.0 |
diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md
index 32cd8f33c650..1d7f42a9075e 100644
--- a/csharp/ql/lib/CHANGELOG.md
+++ b/csharp/ql/lib/CHANGELOG.md
@@ -1,3 +1,42 @@
+## 6.0.0
+
+### Breaking Changes
+
+* The C# control flow graph (CFG) implementation has been completely
+ rewritten. The CFG now includes additional nodes to more accurately represent
+ certain constructs. This also means that any existing code that implicitly
+ relies on very specific details about the CFG may need to be updated.
+ The CFG no longer uses splitting, which means that AST nodes now have a unique
+ CFG node representation.
+ Additionally, the following breaking changes have been made:
+ - `ControlFlow::Node` has been renamed to `ControlFlowNode`.
+ - `ControlFlow::Nodes` has been renamed to `ControlFlowNodes`.
+ - `BasicBlock.getCallable` has been renamed to `BasicBlock.getEnclosingCallable`.
+ - `BasicBlocks.qll` has been deleted.
+ - `ControlFlowNode.getAstNode` has changed its meaning. The AST-to-CFG
+ mapping remains one-to-many, but now for a different reason. It used to be
+ because of splitting, but now it's because of additional "helper" CFG
+ nodes. To get the (now canonical) CFG node for a given AST node, use
+ `ControlFlowNode.asExpr()` or `ControlFlowNode.asStmt()` or
+ `ControlFlowElement.getControlFlowNode()` instead.
+
+### Deprecated APIs
+
+* The QL classes in the C# SSA library have been renamed to improve consistency between languages. Any custom QL code that makes use of SSA needs to be updated. The old classes have been deprecated and include more detailed migration instructions in their qldoc.
+
+### New Features
+
+* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C#](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-csharp/).
+
+### Major Analysis Improvements
+
+* When resolving dependencies in `build-mode: none`, `dotnet restore` now explicitly receives reachable NuGet feeds configured in `nuget.config` when feed responsiveness checking is enabled (the default), and any private registries directly, improving reliability when default feeds are unavailable or restricted.
+
+### Minor Analysis Improvements
+
+* Expanded ASP and ASP.NET remote source modeling to cover additional sources, including fields of tainted parameters as well as properties and fields that become tainted transitively.
+* C# 14: Added support for user-defined compound assignment operators.
+
## 5.5.0
### Deprecated APIs
@@ -64,9 +103,9 @@ No user-facing changes.
* When a code-scanning configuration specifies the `paths:` and/or `paths-ignore:` settings, these are now taken into account by the C# extractor's search for `.config`, `.props`, XML and project files.
* Updated the generated .NET “models as data” runtime models to cover .NET 10.
* C# 14: Support for *implicit* span conversions in the QL library.
-* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
+* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build-mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
* Added autobuilder and `build-mode: none` support for `.slnx` solution files.
-* In `build mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.
+* In `build-mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.
* Added implicit reads of `System.Collections.Generic.KeyValuePair.Value` at taint-tracking sinks and at inputs to additional taint steps. As a result, taint-tracking queries will now produce more results when a container is tainted.
### Bug Fixes
diff --git a/csharp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md b/csharp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md
deleted file mode 100644
index 6408acc7dae8..000000000000
--- a/csharp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: feature
----
-* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C#](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-csharp/).
diff --git a/csharp/ql/lib/change-notes/2026-04-01-asp-remote-sources.md b/csharp/ql/lib/change-notes/2026-04-01-asp-remote-sources.md
deleted file mode 100644
index 52f3f721e9fa..000000000000
--- a/csharp/ql/lib/change-notes/2026-04-01-asp-remote-sources.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Expanded ASP and ASP.NET remote source modeling to cover additional sources, including fields of tainted parameters as well as properties and fields that become tainted transitively.
diff --git a/csharp/ql/lib/change-notes/2026-04-13-cfg.md b/csharp/ql/lib/change-notes/2026-04-13-cfg.md
deleted file mode 100644
index 9c588fbcfa8f..000000000000
--- a/csharp/ql/lib/change-notes/2026-04-13-cfg.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-category: breaking
----
-* The C# control flow graph (CFG) implementation has been completely
- rewritten. The CFG now includes additional nodes to more accurately represent
- certain constructs. This also means that any existing code that implicitly
- relies on very specific details about the CFG may need to be updated.
- The CFG no longer uses splitting, which means that AST nodes now have a unique
- CFG node representation.
- Additionally, the following breaking changes have been made:
- - `ControlFlow::Node` has been renamed to `ControlFlowNode`.
- - `ControlFlow::Nodes` has been renamed to `ControlFlowNodes`.
- - `BasicBlock.getCallable` has been renamed to `BasicBlock.getEnclosingCallable`.
- - `BasicBlocks.qll` has been deleted.
- - `ControlFlowNode.getAstNode` has changed its meaning. The AST-to-CFG
- mapping remains one-to-many, but now for a different reason. It used to be
- because of splitting, but now it's because of additional "helper" CFG
- nodes. To get the (now canonical) CFG node for a given AST node, use
- `ControlFlowNode.asExpr()` or `ControlFlowNode.asStmt()` or
- `ControlFlowElement.getControlFlowNode()` instead.
diff --git a/csharp/ql/lib/change-notes/released/5.4.5.md b/csharp/ql/lib/change-notes/released/5.4.5.md
index a084df5f2008..fc1e8b8c4eeb 100644
--- a/csharp/ql/lib/change-notes/released/5.4.5.md
+++ b/csharp/ql/lib/change-notes/released/5.4.5.md
@@ -5,9 +5,9 @@
* When a code-scanning configuration specifies the `paths:` and/or `paths-ignore:` settings, these are now taken into account by the C# extractor's search for `.config`, `.props`, XML and project files.
* Updated the generated .NET “models as data” runtime models to cover .NET 10.
* C# 14: Support for *implicit* span conversions in the QL library.
-* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
+* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build-mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
* Added autobuilder and `build-mode: none` support for `.slnx` solution files.
-* In `build mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.
+* In `build-mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.
* Added implicit reads of `System.Collections.Generic.KeyValuePair.Value` at taint-tracking sinks and at inputs to additional taint steps. As a result, taint-tracking queries will now produce more results when a container is tainted.
### Bug Fixes
diff --git a/csharp/ql/lib/change-notes/released/6.0.0.md b/csharp/ql/lib/change-notes/released/6.0.0.md
new file mode 100644
index 000000000000..e249567d0958
--- /dev/null
+++ b/csharp/ql/lib/change-notes/released/6.0.0.md
@@ -0,0 +1,38 @@
+## 6.0.0
+
+### Breaking Changes
+
+* The C# control flow graph (CFG) implementation has been completely
+ rewritten. The CFG now includes additional nodes to more accurately represent
+ certain constructs. This also means that any existing code that implicitly
+ relies on very specific details about the CFG may need to be updated.
+ The CFG no longer uses splitting, which means that AST nodes now have a unique
+ CFG node representation.
+ Additionally, the following breaking changes have been made:
+ - `ControlFlow::Node` has been renamed to `ControlFlowNode`.
+ - `ControlFlow::Nodes` has been renamed to `ControlFlowNodes`.
+ - `BasicBlock.getCallable` has been renamed to `BasicBlock.getEnclosingCallable`.
+ - `BasicBlocks.qll` has been deleted.
+ - `ControlFlowNode.getAstNode` has changed its meaning. The AST-to-CFG
+ mapping remains one-to-many, but now for a different reason. It used to be
+ because of splitting, but now it's because of additional "helper" CFG
+ nodes. To get the (now canonical) CFG node for a given AST node, use
+ `ControlFlowNode.asExpr()` or `ControlFlowNode.asStmt()` or
+ `ControlFlowElement.getControlFlowNode()` instead.
+
+### Deprecated APIs
+
+* The QL classes in the C# SSA library have been renamed to improve consistency between languages. Any custom QL code that makes use of SSA needs to be updated. The old classes have been deprecated and include more detailed migration instructions in their qldoc.
+
+### New Features
+
+* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C#](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-csharp/).
+
+### Major Analysis Improvements
+
+* When resolving dependencies in `build-mode: none`, `dotnet restore` now explicitly receives reachable NuGet feeds configured in `nuget.config` when feed responsiveness checking is enabled (the default), and any private registries directly, improving reliability when default feeds are unavailable or restricted.
+
+### Minor Analysis Improvements
+
+* Expanded ASP and ASP.NET remote source modeling to cover additional sources, including fields of tainted parameters as well as properties and fields that become tainted transitively.
+* C# 14: Added support for user-defined compound assignment operators.
diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml
index 4b8cf9533c17..f8c4fa43ccb7 100644
--- a/csharp/ql/lib/codeql-pack.release.yml
+++ b/csharp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 5.5.0
+lastReleaseVersion: 6.0.0
diff --git a/csharp/ql/lib/ext/generated/Generators.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Generators.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Generators.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Generators.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.IBC.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.IBC.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.IBC.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.IBC.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.Amd64.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.Amd64.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.Amd64.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.Amd64.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.Arm.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.Arm.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.Arm.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.Arm.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.Arm64.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.Arm64.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.Arm64.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.Arm64.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.LoongArch64.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.LoongArch64.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.LoongArch64.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.LoongArch64.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.MachO.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.MachO.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.MachO.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.MachO.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.RiscV64.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.RiscV64.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.RiscV64.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.RiscV64.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.x86.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.x86.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.Reflection.ReadyToRun.x86.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.Reflection.ReadyToRun.x86.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILCompiler.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILCompiler.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILCompiler.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.CodeFix.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.CodeFix.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.CodeFix.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.CodeFix.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.RoslynAnalyzer.DataFlow.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.RoslynAnalyzer.DataFlow.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.RoslynAnalyzer.DataFlow.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.RoslynAnalyzer.DataFlow.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.RoslynAnalyzer.TrimAnalysis.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.RoslynAnalyzer.TrimAnalysis.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.RoslynAnalyzer.TrimAnalysis.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.RoslynAnalyzer.TrimAnalysis.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.RoslynAnalyzer.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.RoslynAnalyzer.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.RoslynAnalyzer.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.RoslynAnalyzer.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.Shared.DataFlow.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.DataFlow.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.Shared.DataFlow.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.DataFlow.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.Shared.TrimAnalysis.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.TrimAnalysis.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.Shared.TrimAnalysis.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.TrimAnalysis.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.Shared.TypeSystemProxy.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.TypeSystemProxy.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.Shared.TypeSystemProxy.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.TypeSystemProxy.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.Shared.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.Shared.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.Shared.model.yml
diff --git a/csharp/ql/lib/ext/generated/ILLink.Tasks.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/ILLink.Tasks.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/ILLink.Tasks.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/ILLink.Tasks.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.IL.Stubs.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.IL.Stubs.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.IL.Stubs.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.IL.Stubs.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.IL.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.IL.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.IL.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.IL.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.NativeFormat.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.NativeFormat.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.NativeFormat.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.NativeFormat.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.Pgo.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.Pgo.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.Pgo.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.Pgo.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.TypeSystem.Ecma.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.TypeSystem.Ecma.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.TypeSystem.Ecma.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.TypeSystem.Ecma.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.TypeSystem.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.TypeSystem.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.TypeSystem.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.TypeSystem.model.yml
diff --git a/csharp/ql/lib/ext/generated/Internal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Internal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Internal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Internal.model.yml
diff --git a/csharp/ql/lib/ext/generated/IntrinsicsInSystemPrivateCoreLib.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/IntrinsicsInSystemPrivateCoreLib.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/IntrinsicsInSystemPrivateCoreLib.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/IntrinsicsInSystemPrivateCoreLib.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.CSharp.RuntimeBinder.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.CSharp.RuntimeBinder.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.CSharp.RuntimeBinder.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.CSharp.RuntimeBinder.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.CSharp.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.CSharp.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.CSharp.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.CSharp.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Diagnostics.JitTrace.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Diagnostics.JitTrace.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Diagnostics.JitTrace.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Diagnostics.JitTrace.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Diagnostics.Tools.Pgo.TypeRefTypeSystem.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Diagnostics.Tools.Pgo.TypeRefTypeSystem.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Diagnostics.Tools.Pgo.TypeRefTypeSystem.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Diagnostics.Tools.Pgo.TypeRefTypeSystem.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Diagnostics.Tools.Pgo.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Diagnostics.Tools.Pgo.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Diagnostics.Tools.Pgo.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Diagnostics.Tools.Pgo.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.DotNet.Build.Tasks.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.DotNet.Build.Tasks.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.DotNet.Build.Tasks.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.DotNet.Build.Tasks.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.DotNet.PlatformAbstractions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.DotNet.PlatformAbstractions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.DotNet.PlatformAbstractions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.DotNet.PlatformAbstractions.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Caching.Distributed.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Caching.Distributed.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Caching.Distributed.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Caching.Distributed.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Caching.Hybrid.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Caching.Hybrid.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Caching.Hybrid.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Caching.Hybrid.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Caching.Memory.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Caching.Memory.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Caching.Memory.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Caching.Memory.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Binder.SourceGeneration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Binder.SourceGeneration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Binder.SourceGeneration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Binder.SourceGeneration.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.CommandLine.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.CommandLine.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.CommandLine.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.CommandLine.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.EnvironmentVariables.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.EnvironmentVariables.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.EnvironmentVariables.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.EnvironmentVariables.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Ini.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Ini.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Ini.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Ini.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Json.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Json.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Json.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Json.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Memory.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Memory.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Memory.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Memory.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.UserSecrets.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.UserSecrets.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.UserSecrets.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.UserSecrets.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Xml.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Xml.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.Xml.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.Xml.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Configuration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Configuration.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.Extensions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.Extensions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.Extensions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.Extensions.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.Specification.Fakes.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.Specification.Fakes.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.Specification.Fakes.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.Specification.Fakes.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.Specification.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.Specification.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.Specification.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.Specification.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyInjection.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyInjection.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyModel.Resolution.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyModel.Resolution.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyModel.Resolution.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyModel.Resolution.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyModel.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyModel.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.DependencyModel.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.DependencyModel.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Diagnostics.Metrics.Configuration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Diagnostics.Metrics.Configuration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Diagnostics.Metrics.Configuration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Diagnostics.Metrics.Configuration.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Diagnostics.Metrics.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Diagnostics.Metrics.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Diagnostics.Metrics.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Diagnostics.Metrics.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.Composite.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.Composite.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.Composite.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.Composite.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.Internal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.Internal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.Internal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.Internal.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.Physical.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.Physical.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.Physical.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.Physical.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileProviders.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileProviders.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Abstractions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Abstractions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Abstractions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Abstractions.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.PathSegments.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.PathSegments.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.PathSegments.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.PathSegments.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.PatternContexts.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.PatternContexts.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.PatternContexts.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.PatternContexts.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.Patterns.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.Patterns.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.Patterns.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.Patterns.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.Internal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.Internal.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.FileSystemGlobbing.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.FileSystemGlobbing.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.Internal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.Internal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.Internal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.Internal.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.Systemd.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.Systemd.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.Systemd.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.Systemd.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.WindowsServices.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.WindowsServices.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.WindowsServices.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.WindowsServices.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Hosting.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Hosting.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Http.Logging.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Http.Logging.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Http.Logging.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Http.Logging.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Http.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Http.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Http.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Http.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Internal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Internal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Internal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Internal.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Abstractions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Abstractions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Abstractions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Abstractions.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Configuration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Configuration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Configuration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Configuration.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Console.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Console.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Console.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Console.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Debug.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Debug.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Debug.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Debug.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.EventLog.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.EventLog.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.EventLog.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.EventLog.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.EventSource.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.EventSource.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.EventSource.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.EventSource.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Generators.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Generators.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.Generators.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.Generators.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.TraceSource.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.TraceSource.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.TraceSource.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.TraceSource.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Logging.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Logging.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Options.Generators.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Options.Generators.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Options.Generators.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Options.Generators.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Options.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Options.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Options.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Options.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Extensions.Primitives.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Primitives.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Extensions.Primitives.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Extensions.Primitives.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Interop.Analyzers.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Interop.Analyzers.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Interop.Analyzers.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Interop.Analyzers.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Interop.JavaScript.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Interop.JavaScript.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Interop.JavaScript.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Interop.JavaScript.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Interop.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Interop.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Interop.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Interop.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.NET.Build.Tasks.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.NET.Build.Tasks.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.NET.Build.Tasks.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.NET.Build.Tasks.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.NETCore.Platforms.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.NETCore.Platforms.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.NETCore.Platforms.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.NETCore.Platforms.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.VisualBasic.CompilerServices.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.VisualBasic.CompilerServices.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.VisualBasic.CompilerServices.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.VisualBasic.CompilerServices.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.VisualBasic.FileIO.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.VisualBasic.FileIO.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.VisualBasic.FileIO.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.VisualBasic.FileIO.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.VisualBasic.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.VisualBasic.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.VisualBasic.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.VisualBasic.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Win32.SafeHandles.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Win32.SafeHandles.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Win32.SafeHandles.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Win32.SafeHandles.model.yml
diff --git a/csharp/ql/lib/ext/generated/Microsoft.Win32.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Win32.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Microsoft.Win32.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Microsoft.Win32.model.yml
diff --git a/csharp/ql/lib/ext/generated/Mono.Linker.Dataflow.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Mono.Linker.Dataflow.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Mono.Linker.Dataflow.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Mono.Linker.Dataflow.model.yml
diff --git a/csharp/ql/lib/ext/generated/Mono.Linker.Steps.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Mono.Linker.Steps.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Mono.Linker.Steps.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Mono.Linker.Steps.model.yml
diff --git a/csharp/ql/lib/ext/generated/Mono.Linker.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/Mono.Linker.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/Mono.Linker.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/Mono.Linker.model.yml
diff --git a/csharp/ql/lib/ext/generated/SourceGenerators.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/SourceGenerators.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/SourceGenerators.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/SourceGenerators.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Buffers.Binary.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Buffers.Binary.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Buffers.Binary.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Buffers.Binary.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Buffers.Text.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Buffers.Text.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Buffers.Text.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Buffers.Text.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Buffers.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Buffers.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Buffers.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Buffers.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.CodeDom.Compiler.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.CodeDom.Compiler.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.CodeDom.Compiler.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.CodeDom.Compiler.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.CodeDom.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.CodeDom.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.CodeDom.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.CodeDom.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.Concurrent.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Concurrent.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.Concurrent.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Concurrent.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.Frozen.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Frozen.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.Frozen.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Frozen.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.Generic.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Generic.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.Generic.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Generic.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.Immutable.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Immutable.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.Immutable.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Immutable.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.ObjectModel.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.ObjectModel.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.ObjectModel.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.ObjectModel.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.Specialized.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Specialized.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.Specialized.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.Specialized.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Collections.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Collections.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Collections.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Collections.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Composition.Hosting.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.Hosting.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Composition.Hosting.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.Hosting.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Composition.Primitives.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.Primitives.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Composition.Primitives.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.Primitives.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Composition.ReflectionModel.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.ReflectionModel.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Composition.ReflectionModel.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.ReflectionModel.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Composition.Registration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.Registration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Composition.Registration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.Registration.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Composition.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Composition.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Composition.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.DataAnnotations.Schema.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.DataAnnotations.Schema.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.DataAnnotations.Schema.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.DataAnnotations.Schema.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.DataAnnotations.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.DataAnnotations.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.DataAnnotations.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.DataAnnotations.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Design.Serialization.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Design.Serialization.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Design.Serialization.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Design.Serialization.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.Design.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Design.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.Design.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.Design.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ComponentModel.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ComponentModel.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ComponentModel.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Composition.Convention.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Composition.Convention.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Composition.Convention.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Composition.Convention.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Composition.Hosting.Core.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Composition.Hosting.Core.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Composition.Hosting.Core.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Composition.Hosting.Core.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Composition.Hosting.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Composition.Hosting.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Composition.Hosting.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Composition.Hosting.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Composition.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Composition.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Composition.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Composition.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Configuration.Internal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Configuration.Internal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Configuration.Internal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Configuration.Internal.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Configuration.Provider.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Configuration.Provider.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Configuration.Provider.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Configuration.Provider.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Configuration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Configuration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Configuration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Configuration.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.Common.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.Common.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.Common.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.Common.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.Odbc.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.Odbc.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.Odbc.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.Odbc.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.OleDb.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.OleDb.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.OleDb.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.OleDb.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.OracleClient.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.OracleClient.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.OracleClient.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.OracleClient.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.SqlClient.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.SqlClient.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.SqlClient.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.SqlClient.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.SqlTypes.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.SqlTypes.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.SqlTypes.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.SqlTypes.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Data.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Data.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Data.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Data.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.CodeAnalysis.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.CodeAnalysis.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.CodeAnalysis.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.CodeAnalysis.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.Contracts.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Contracts.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.Contracts.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Contracts.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.Eventing.Reader.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Eventing.Reader.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.Eventing.Reader.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Eventing.Reader.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.Metrics.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Metrics.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.Metrics.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Metrics.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.PerformanceData.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.PerformanceData.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.PerformanceData.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.PerformanceData.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.SymbolStore.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.SymbolStore.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.SymbolStore.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.SymbolStore.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.Tracing.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Tracing.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.Tracing.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.Tracing.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Diagnostics.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Diagnostics.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Diagnostics.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.DirectoryServices.AccountManagement.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.AccountManagement.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.DirectoryServices.AccountManagement.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.AccountManagement.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.DirectoryServices.ActiveDirectory.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.ActiveDirectory.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.DirectoryServices.ActiveDirectory.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.ActiveDirectory.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.DirectoryServices.Protocols.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.Protocols.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.DirectoryServices.Protocols.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.Protocols.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.DirectoryServices.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.DirectoryServices.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.DirectoryServices.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Drawing.Printing.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Drawing.Printing.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Drawing.Printing.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Drawing.Printing.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Drawing.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Drawing.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Drawing.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Drawing.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Dynamic.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Dynamic.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Dynamic.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Dynamic.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Formats.Asn1.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Asn1.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Formats.Asn1.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Asn1.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Formats.Cbor.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Cbor.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Formats.Cbor.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Cbor.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Formats.Nrbf.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Nrbf.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Formats.Nrbf.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Nrbf.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Formats.Tar.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Tar.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Formats.Tar.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Formats.Tar.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Globalization.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Globalization.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Globalization.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Globalization.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Compression.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Compression.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Compression.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Compression.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Enumeration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Enumeration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Enumeration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Enumeration.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Hashing.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Hashing.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Hashing.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Hashing.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.IsolatedStorage.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.IsolatedStorage.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.IsolatedStorage.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.IsolatedStorage.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.MemoryMappedFiles.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.MemoryMappedFiles.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.MemoryMappedFiles.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.MemoryMappedFiles.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Packaging.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Packaging.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Packaging.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Packaging.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Pipelines.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Pipelines.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Pipelines.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Pipelines.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Pipes.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Pipes.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Pipes.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Pipes.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.Ports.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.Ports.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.Ports.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.Ports.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.IO.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.IO.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.IO.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.IO.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Linq.Expressions.Interpreter.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Linq.Expressions.Interpreter.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Linq.Expressions.Interpreter.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Linq.Expressions.Interpreter.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Linq.Expressions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Linq.Expressions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Linq.Expressions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Linq.Expressions.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Linq.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Linq.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Linq.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Linq.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Management.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Management.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Management.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Management.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Media.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Media.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Media.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Media.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Cache.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Cache.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Cache.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Cache.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Http.Headers.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.Headers.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Http.Headers.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.Headers.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Http.Json.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.Json.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Http.Json.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.Json.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Http.Metrics.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.Metrics.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Http.Metrics.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.Metrics.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Http.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Http.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Http.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Mail.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Mail.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Mail.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Mail.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Mime.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Mime.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Mime.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Mime.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.NetworkInformation.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.NetworkInformation.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.NetworkInformation.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.NetworkInformation.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.PeerToPeer.Collaboration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.PeerToPeer.Collaboration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.PeerToPeer.Collaboration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.PeerToPeer.Collaboration.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.PeerToPeer.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.PeerToPeer.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.PeerToPeer.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.PeerToPeer.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Quic.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Quic.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Quic.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Quic.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Security.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Security.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Security.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Security.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.ServerSentEvents.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.ServerSentEvents.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.ServerSentEvents.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.ServerSentEvents.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.Sockets.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.Sockets.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.Sockets.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.Sockets.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.WebSockets.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.WebSockets.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.WebSockets.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.WebSockets.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Net.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Net.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Net.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Net.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Numerics.Tensors.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Numerics.Tensors.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Numerics.Tensors.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Numerics.Tensors.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Numerics.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Numerics.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Numerics.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Numerics.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Reflection.Context.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Context.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Reflection.Context.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Context.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Reflection.Emit.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Emit.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Reflection.Emit.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Emit.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Reflection.Metadata.Ecma335.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Metadata.Ecma335.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Reflection.Metadata.Ecma335.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Metadata.Ecma335.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Reflection.Metadata.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Metadata.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Reflection.Metadata.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.Metadata.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Reflection.PortableExecutable.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.PortableExecutable.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Reflection.PortableExecutable.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.PortableExecutable.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Reflection.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Reflection.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Reflection.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Resources.Extensions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Resources.Extensions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Resources.Extensions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Resources.Extensions.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Resources.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Resources.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Resources.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Resources.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Caching.Hosting.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Caching.Hosting.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Caching.Hosting.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Caching.Hosting.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Caching.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Caching.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Caching.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Caching.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.CompilerServices.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.CompilerServices.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.CompilerServices.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.CompilerServices.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.ConstrainedExecution.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.ConstrainedExecution.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.ConstrainedExecution.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.ConstrainedExecution.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.ExceptionServices.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.ExceptionServices.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.ExceptionServices.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.ExceptionServices.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.ComTypes.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.ComTypes.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.ComTypes.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.ComTypes.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.Java.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.Java.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.Java.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.Java.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.JavaScript.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.JavaScript.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.JavaScript.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.JavaScript.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.Marshalling.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.Marshalling.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.Marshalling.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.Marshalling.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.ObjectiveC.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.ObjectiveC.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.ObjectiveC.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.ObjectiveC.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.Swift.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.Swift.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.Swift.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.Swift.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.InteropServices.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.InteropServices.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.InteropServices.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.Arm.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.Arm.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.Arm.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.Arm.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.Wasm.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.Wasm.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.Wasm.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.Wasm.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.X86.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.X86.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.X86.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.X86.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Intrinsics.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Intrinsics.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Loader.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Loader.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Loader.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Loader.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Remoting.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Remoting.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Remoting.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Remoting.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Serialization.DataContracts.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.DataContracts.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Serialization.DataContracts.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.DataContracts.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Serialization.Formatters.Binary.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.Formatters.Binary.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Serialization.Formatters.Binary.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.Formatters.Binary.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Serialization.Json.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.Json.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Serialization.Json.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.Json.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Serialization.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Serialization.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Serialization.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.Versioning.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Versioning.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.Versioning.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.Versioning.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Runtime.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Runtime.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Runtime.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.AccessControl.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.AccessControl.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.AccessControl.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.AccessControl.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Authentication.ExtendedProtection.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Authentication.ExtendedProtection.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Authentication.ExtendedProtection.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Authentication.ExtendedProtection.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Authentication.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Authentication.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Authentication.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Authentication.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Claims.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Claims.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Claims.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Claims.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Cryptography.Cose.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.Cose.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Cryptography.Cose.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.Cose.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Cryptography.Pkcs.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.Pkcs.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Cryptography.Pkcs.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.Pkcs.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Cryptography.X509Certificates.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.X509Certificates.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Cryptography.X509Certificates.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.X509Certificates.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Cryptography.Xml.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.Xml.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Cryptography.Xml.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.Xml.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Cryptography.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Cryptography.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Cryptography.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Permissions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Permissions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Permissions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Permissions.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Policy.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Policy.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Policy.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Policy.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.Principal.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.Principal.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.Principal.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.Principal.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Security.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Security.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Security.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Security.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ServiceModel.Syndication.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ServiceModel.Syndication.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ServiceModel.Syndication.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ServiceModel.Syndication.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.ServiceProcess.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.ServiceProcess.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.ServiceProcess.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.ServiceProcess.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Speech.AudioFormat.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Speech.AudioFormat.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Speech.AudioFormat.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Speech.AudioFormat.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Speech.Recognition.SrgsGrammar.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Recognition.SrgsGrammar.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Speech.Recognition.SrgsGrammar.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Recognition.SrgsGrammar.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Speech.Recognition.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Recognition.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Speech.Recognition.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Recognition.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Speech.Synthesis.TtsEngine.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Synthesis.TtsEngine.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Speech.Synthesis.TtsEngine.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Synthesis.TtsEngine.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Speech.Synthesis.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Synthesis.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Speech.Synthesis.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Speech.Synthesis.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Encodings.Web.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Encodings.Web.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Encodings.Web.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Encodings.Web.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Json.Nodes.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Nodes.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Json.Nodes.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Nodes.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Json.Schema.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Schema.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Json.Schema.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Schema.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Json.Serialization.Metadata.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Serialization.Metadata.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Json.Serialization.Metadata.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Serialization.Metadata.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Json.Serialization.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Serialization.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Json.Serialization.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.Serialization.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Json.SourceGeneration.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.SourceGeneration.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Json.SourceGeneration.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.SourceGeneration.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Json.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Json.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Json.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.RegularExpressions.Generator.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.RegularExpressions.Generator.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.RegularExpressions.Generator.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.RegularExpressions.Generator.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.RegularExpressions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.RegularExpressions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.RegularExpressions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.RegularExpressions.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.Unicode.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.Unicode.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.Unicode.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.Unicode.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Text.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Text.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Text.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Text.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Threading.Channels.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Channels.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Threading.Channels.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Channels.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Threading.RateLimiting.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Threading.RateLimiting.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Threading.RateLimiting.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Threading.RateLimiting.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Threading.Tasks.Dataflow.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Tasks.Dataflow.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Threading.Tasks.Dataflow.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Tasks.Dataflow.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Threading.Tasks.Sources.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Tasks.Sources.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Threading.Tasks.Sources.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Tasks.Sources.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Threading.Tasks.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Tasks.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Threading.Tasks.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Threading.Tasks.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Threading.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Threading.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Threading.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Threading.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Timers.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Timers.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Timers.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Timers.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Transactions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Transactions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Transactions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Transactions.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Web.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Web.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Web.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Web.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Windows.Input.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Windows.Input.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Windows.Input.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Windows.Input.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Windows.Markup.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Windows.Markup.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Windows.Markup.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Windows.Markup.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xaml.Permissions.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xaml.Permissions.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xaml.Permissions.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xaml.Permissions.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.Linq.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Linq.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.Linq.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Linq.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.Resolvers.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Resolvers.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.Resolvers.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Resolvers.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.Schema.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Schema.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.Schema.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Schema.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.Serialization.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Serialization.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.Serialization.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Serialization.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.XPath.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.XPath.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.XPath.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.XPath.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.Xsl.Runtime.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Xsl.Runtime.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.Xsl.Runtime.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Xsl.Runtime.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.Xsl.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Xsl.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.Xsl.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.Xsl.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.Xml.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.Xml.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.Xml.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.Xml.model.yml
diff --git a/csharp/ql/lib/ext/generated/System.model.yml b/csharp/ql/lib/ext/generated/modelgenerator/System.model.yml
similarity index 100%
rename from csharp/ql/lib/ext/generated/System.model.yml
rename to csharp/ql/lib/ext/generated/modelgenerator/System.model.yml
diff --git a/csharp/ql/lib/printCfg.ql b/csharp/ql/lib/printCfg.ql
index c418446b2164..c9910428bb09 100644
--- a/csharp/ql/lib/printCfg.ql
+++ b/csharp/ql/lib/printCfg.ql
@@ -8,6 +8,7 @@
*/
import csharp
+import semmle.code.csharp.controlflow.internal.ControlFlowGraph
external string selectedSourceFile();
@@ -22,6 +23,8 @@ external int selectedSourceColumn();
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig {
+ private import semmle.code.csharp.controlflow.ControlFlowGraph
+
predicate selectedSourceFile = selectedSourceFileAlias/0;
predicate selectedSourceLine = selectedSourceLineAlias/0;
@@ -29,7 +32,7 @@ module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig {
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
predicate cfgScopeSpan(
- Callable scope, File file, int startLine, int startColumn, int endLine, int endColumn
+ Ast::Callable scope, File file, int startLine, int startColumn, int endLine, int endColumn
) {
file = scope.getFile() and
scope.getLocation().getStartLine() = startLine and
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index 7c906e033ad6..0e03db99ca91 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 5.5.1-dev
+version: 6.0.1-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
@@ -16,6 +16,6 @@ dependencies:
codeql/xml: ${workspace}
dataExtensions:
- ext/*.model.yml
- - ext/generated/*.model.yml
+ - ext/generated/**/*.model.yml
warnOnImplicitThis: true
compileForOverlayEval: true
diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll
index af6861349d1c..7bd432d48ce4 100644
--- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll
@@ -271,6 +271,8 @@ module AssignableInternal {
def = TPatternDefinition(result)
or
def = TAssignOperationDefinition(result)
+ or
+ def = TParameterDefaultDefinition(_, result)
}
/** A local variable declaration at the top-level of a pattern. */
@@ -308,14 +310,22 @@ module AssignableInternal {
exists(Callable c | p = c.getAParameter() |
c.hasBody()
or
- // Same as `c.(Constructor).hasInitializer()`, but avoids negative recursion warning
- c.getAChildExpr() instanceof @constructor_init_expr
+ c.(Constructor).hasInitializer()
)
} or
+ TParameterDefaultDefinition(Parameter p, Expr default) {
+ exists(Callable c | p = c.getAParameter() |
+ c.hasBody()
+ or
+ c.(Constructor).hasInitializer()
+ ) and
+ default = p.getDefaultValue()
+ } or
TAddressOfDefinition(AddressOfExpr aoe) or
TPatternDefinition(TopLevelPatternDecl tlpd) or
TAssignOperationDefinition(AssignOperation ao) {
- ao instanceof AssignCallOperation or
+ ao instanceof AssignCallOperation and not ao instanceof CompoundAssignmentOperatorCall
+ or
ao instanceof AssignCoalesceExpr
}
@@ -349,6 +359,8 @@ module AssignableInternal {
any(AssignableDefinitions::PatternDefinition pd | result = pd.getDeclaration().getVariable())
or
def = any(AssignableDefinitions::InitializerDefinition init | result = init.getAssignable())
+ or
+ def = TParameterDefaultDefinition(result, _)
}
// Not defined by dispatch in order to avoid too conservative negative recursion error
@@ -488,16 +500,7 @@ class AssignableDefinition extends TAssignableDefinition {
*/
pragma[nomagic]
AssignableRead getAFirstRead() {
- exists(ControlFlowNode cfn | cfn = result.getControlFlowNode() |
- exists(Ssa::ExplicitDefinition def | result = def.getAFirstReadAtNode(cfn) |
- this = def.getADefinition()
- )
- or
- exists(Ssa::ImplicitParameterDefinition def | result = def.getAFirstReadAtNode(cfn) |
- this.(AssignableDefinitions::ImplicitParameterDefinition).getParameter() =
- def.getParameter()
- )
- )
+ exists(SsaExplicitWrite def | result = Ssa::ssaGetAFirstUse(def) | this = def.getDefinition())
}
/** Gets a textual representation of this assignable definition. */
@@ -688,7 +691,33 @@ module AssignableDefinitions {
override string toString() { result = p.toString() }
- override Location getLocation() { result = this.getTarget().getLocation() }
+ override Location getLocation() { result = p.getLocation() }
+ }
+
+ /**
+ * A default value assigned to a parameter.
+ */
+ class ParameterDefaultDefinition extends AssignableDefinition, TParameterDefaultDefinition {
+ Parameter p;
+ Expr default;
+
+ ParameterDefaultDefinition() { this = TParameterDefaultDefinition(p, default) }
+
+ /** Gets the underlying parameter. */
+ Parameter getParameter() { result = p }
+
+ /** Gets the default value expression for the parameter. */
+ Expr getDefaultValue() { result = default }
+
+ override Expr getSource() { result = default }
+
+ override Expr getElement() { result = default }
+
+ override Callable getEnclosingCallable() { result = p.getCallable() }
+
+ override string toString() { result = p.toString() + " = ..." }
+
+ override Location getLocation() { result = default.getLocation() }
}
/**
diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll
index 7859c7ea1d0e..9416a7d4d9c7 100644
--- a/csharp/ql/lib/semmle/code/csharp/Callable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll
@@ -611,7 +611,8 @@ class ExtensionOperator extends ExtensionCallableImpl, Operator {
class UnaryOperator extends Operator {
UnaryOperator() {
this.getNumberOfParameters() = 1 and
- not this instanceof ConversionOperator
+ not this instanceof ConversionOperator and
+ not this instanceof CompoundAssignmentOperator
}
}
@@ -784,7 +785,7 @@ class TrueOperator extends UnaryOperator {
* A user-defined binary operator.
*
* Either an addition operator (`AddOperator`), a checked addition operator
- * (`CheckedAddOperator`) a subtraction operator (`SubOperator`), a checked
+ * (`CheckedAddOperator`), a subtraction operator (`SubOperator`), a checked
* subtraction operator (`CheckedSubOperator`), a multiplication operator
* (`MulOperator`), a checked multiplication operator (`CheckedMulOperator`),
* a division operator (`DivOperator`), a checked division operator
@@ -795,10 +796,16 @@ class TrueOperator extends UnaryOperator {
* operator(`UnsignedRightShiftOperator`), an equals operator (`EQOperator`),
* a not equals operator (`NEOperator`), a lesser than operator (`LTOperator`),
* a greater than operator (`GTOperator`), a less than or equals operator
- * (`LEOperator`), or a greater than or equals operator (`GEOperator`).
+ * (`LEOperator`), a greater than or equals operator (`GEOperator`), or
+ * a compound assignment operator (`CompoundAssignmentOperator`).
*/
class BinaryOperator extends Operator {
- BinaryOperator() { this.getNumberOfParameters() = 2 }
+ BinaryOperator() {
+ this.getNumberOfParameters() = 2
+ or
+ // Instance compound assignment operators only have one parameter.
+ this.getNumberOfParameters() = 1 and not this.isStatic()
+ }
}
/**
@@ -1184,6 +1191,249 @@ class CheckedExplicitConversionOperator extends ConversionOperator {
override string getAPrimaryQlClass() { result = "CheckedExplicitConversionOperator" }
}
+abstract private class CompoundAssignmentOperatorImpl extends BinaryOperator { }
+
+/**
+ * A user-defined compound assignment operator.
+ *
+ * Either an addition operator (`AddCompoundAssignmentOperator`), a checked addition operator
+ * (`CheckedAddCompoundAssignmentOperator`), a subtraction operator (`SubCompoundAssignmentOperator`), a checked
+ * subtraction operator (`CheckedSubCompoundAssignmentOperator`), a multiplication operator
+ * (`MulCompoundAssignmentOperator`), a checked multiplication operator (`CheckedMulCompoundAssignmentOperator`),
+ * a division operator (`DivCompoundAssignmentOperator`), a checked division operator
+ * (`CheckedDivCompoundAssignmentOperator`), a remainder operator (`RemCompoundAssignmentOperator`), an and
+ * operator (`AndCompoundAssignmentOperator`), an or operator (`OrCompoundAssignmentOperator`), an xor
+ * operator (`XorCompoundAssignmentOperator`), a left shift operator (`LeftShiftCompoundAssignmentOperator`),
+ * a right shift operator (`RightShiftCompoundAssignmentOperator`), or an unsigned right shift
+ * operator(`UnsignedRightShiftCompoundAssignmentOperator`).
+ */
+final class CompoundAssignmentOperator = CompoundAssignmentOperatorImpl;
+
+/**
+ * A user-defined compound assignment addition operator (`+=`), for example
+ *
+ * ```csharp
+ * public void operator checked +=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class AddCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ AddCompoundAssignmentOperator() { this.getName() = "+=" }
+
+ override string getAPrimaryQlClass() { result = "AddCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined checked compound assignment addition operator (`checked +=`), for example
+ *
+ * ```csharp
+ * public void operator checked +=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class CheckedAddCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ CheckedAddCompoundAssignmentOperator() { this.getName() = "checked +=" }
+
+ override string getAPrimaryQlClass() { result = "CheckedAddCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment subtraction operator (`-=`), for example
+ *
+ * ```csharp
+ * public void operator -=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class SubCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ SubCompoundAssignmentOperator() { this.getName() = "-=" }
+
+ override string getAPrimaryQlClass() { result = "SubCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined checked compound assignment subtraction operator (`checked -=`), for example
+ *
+ * ```csharp
+ * public void operator checked -=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class CheckedSubCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ CheckedSubCompoundAssignmentOperator() { this.getName() = "checked -=" }
+
+ override string getAPrimaryQlClass() { result = "CheckedSubCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment multiplication operator (`*=`), for example
+ *
+ * ```csharp
+ * public void operator *=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class MulCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ MulCompoundAssignmentOperator() { this.getName() = "*=" }
+
+ override string getAPrimaryQlClass() { result = "MulCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined checked compound assignment multiplication operator (`checked *=`), for example
+ *
+ * ```csharp
+ * public void operator checked *=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class CheckedMulCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ CheckedMulCompoundAssignmentOperator() { this.getName() = "checked *=" }
+
+ override string getAPrimaryQlClass() { result = "CheckedMulCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment division operator (`/=`), for example
+ *
+ * ```csharp
+ * public void operator /=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class DivCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ DivCompoundAssignmentOperator() { this.getName() = "/=" }
+
+ override string getAPrimaryQlClass() { result = "DivCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined checked compound assignment division operator (`checked /=`), for example
+ *
+ * ```csharp
+ * public void operator checked /=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class CheckedDivCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ CheckedDivCompoundAssignmentOperator() { this.getName() = "checked /=" }
+
+ override string getAPrimaryQlClass() { result = "CheckedDivCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment remainder operator (`%=`), for example
+ *
+ * ```csharp
+ * public void operator %=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class RemCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ RemCompoundAssignmentOperator() { this.getName() = "%=" }
+
+ override string getAPrimaryQlClass() { result = "RemCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment and operator (`&=`), for example
+ *
+ * ```csharp
+ * public void operator &=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class AndCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ AndCompoundAssignmentOperator() { this.getName() = "&=" }
+
+ override string getAPrimaryQlClass() { result = "AndCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment or operator (`|=`), for example
+ *
+ * ```csharp
+ * public void operator |=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class OrCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ OrCompoundAssignmentOperator() { this.getName() = "|=" }
+
+ override string getAPrimaryQlClass() { result = "OrCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment xor operator (`^=`), for example
+ *
+ * ```csharp
+ * public void operator ^=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class XorCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ XorCompoundAssignmentOperator() { this.getName() = "^=" }
+
+ override string getAPrimaryQlClass() { result = "XorCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment left shift operator (`<<=`), for example
+ *
+ * ```csharp
+ * public void operator <<=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class LeftShiftCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ LeftShiftCompoundAssignmentOperator() { this.getName() = "<<=" }
+
+ override string getAPrimaryQlClass() { result = "LeftShiftCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment right shift operator (`>>=`), for example
+ *
+ * ```csharp
+ * public void operator >>=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class RightShiftCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ RightShiftCompoundAssignmentOperator() { this.getName() = ">>=" }
+
+ override string getAPrimaryQlClass() { result = "RightShiftCompoundAssignmentOperator" }
+}
+
+/**
+ * A user-defined compound assignment unsigned right shift operator (`>>>=`), for example
+ *
+ * ```csharp
+ * public void operator >>>=(Widget w) {
+ * ...
+ * }
+ * ```
+ */
+class UnsignedRightShiftCompoundAssignmentOperator extends CompoundAssignmentOperatorImpl {
+ UnsignedRightShiftCompoundAssignmentOperator() { this.getName() = ">>>=" }
+
+ override string getAPrimaryQlClass() { result = "UnsignedRightShiftCompoundAssignmentOperator" }
+}
+
/**
* A local function, defined within the scope of another callable.
* For example, `Fac` on lines 2--4 in
diff --git a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll
index 1aa558194e3a..2cf09707459d 100644
--- a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll
+++ b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll
@@ -13,7 +13,7 @@ private import internal.Location
* An element that can have a child statement or expression.
*/
class ExprOrStmtParent extends Element, @exprorstmt_parent {
- final override ControlFlowElement getChild(int i) {
+ override ControlFlowElement getChild(int i) {
result = this.getChildExpr(i) or
result = this.getChildStmt(i)
}
@@ -42,14 +42,8 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
*
* An element that can have a child top-level expression.
*/
-class TopLevelExprParent extends Element, @top_level_expr_parent {
+class TopLevelExprParent extends ExprOrStmtParent, @top_level_expr_parent {
final override Expr getChild(int i) { result = this.getChildExpr(i) }
-
- /** Gets the `i`th child expression of this element (zero-based). */
- final Expr getChildExpr(int i) { expr_parent_top_level_adjusted(result, i, this) }
-
- /** Gets a child expression of this element, if any. */
- final Expr getAChildExpr() { result = this.getChildExpr(_) }
}
/** INTERNAL: Do not use. */
diff --git a/csharp/ql/lib/semmle/code/csharp/PrintAst.qll b/csharp/ql/lib/semmle/code/csharp/PrintAst.qll
index 1fab6b0f8c45..3b328c8393e6 100644
--- a/csharp/ql/lib/semmle/code/csharp/PrintAst.qll
+++ b/csharp/ql/lib/semmle/code/csharp/PrintAst.qll
@@ -299,7 +299,9 @@ class ControlFlowElementNode extends ElementNode {
not isNotNeeded(element.getParent+()) and
// LambdaExpr is both a Callable and a ControlFlowElement,
// print it with the more specific CallableNode
- not element instanceof Callable
+ not element instanceof Callable and
+ // Handled in `ParameterNode`
+ not element instanceof Parameter
}
override PrintAstNode getChild(int childIndex) {
diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll
index 54bbe9a6219f..7af167cd9bcb 100644
--- a/csharp/ql/lib/semmle/code/csharp/Type.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Type.qll
@@ -1334,6 +1334,7 @@ class TypeMention extends @type_mention {
* ```csharp
* static class MyExtensions {
* extension(string s) { ... }
+ * }
* ```
*/
class ExtensionType extends Parameterizable, @extension_type {
diff --git a/csharp/ql/lib/semmle/code/csharp/Variable.qll b/csharp/ql/lib/semmle/code/csharp/Variable.qll
index 6d59816373d2..2d4cf578436d 100644
--- a/csharp/ql/lib/semmle/code/csharp/Variable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Variable.qll
@@ -87,7 +87,9 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
* }
* ```
*/
-class Parameter extends LocalScopeVariable, Attributable, TopLevelExprParent, @parameter {
+class Parameter extends LocalScopeVariable, Attributable, TopLevelExprParent, ControlFlowElement,
+ @parameter
+{
/** Gets the raw position of this parameter, including the `this` parameter at index 0. */
final int getRawPosition() { this = this.getDeclaringElement().getRawParameter(result) }
diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
index 09f65034f6d6..c56d3dab420c 100644
--- a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
+++ b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
@@ -3,7 +3,7 @@
*/
import csharp
-private import codeql.controlflow.ControlFlowGraph
+private import internal.ControlFlowGraph
private import codeql.controlflow.SuccessorType
private import semmle.code.csharp.commons.Compilation
private import semmle.code.csharp.controlflow.internal.NonReturning as NonReturning
@@ -19,197 +19,6 @@ private import Cfg1
private import Cfg2
import Public
-/** Provides an implementation of the AST signature for C#. */
-private module Ast implements AstSig {
- private import csharp as CS
-
- class AstNode = ControlFlowElementOrCallable;
-
- additional predicate skipControlFlow(AstNode e) {
- e instanceof TypeAccess and
- not e instanceof TypeAccessPatternExpr
- or
- not e.getFile().fromSource()
- }
-
- private AstNode getExprChild0(Expr e, int i) {
- not e instanceof NameOfExpr and
- not e instanceof AnonymousFunctionExpr and
- not skipControlFlow(result) and
- result = e.getChild(i)
- }
-
- private AstNode getStmtChild0(Stmt s, int i) {
- not s instanceof FixedStmt and
- not s instanceof UsingBlockStmt and
- result = s.getChild(i)
- or
- s =
- any(FixedStmt fs |
- result = fs.getVariableDeclExpr(i)
- or
- result = fs.getBody() and
- i = max(int j | exists(fs.getVariableDeclExpr(j))) + 1
- )
- or
- s =
- any(UsingBlockStmt us |
- result = us.getExpr() and
- i = 0
- or
- result = us.getVariableDeclExpr(i)
- or
- result = us.getBody() and
- i = max([1, count(us.getVariableDeclExpr(_))])
- )
- }
-
- AstNode getChild(AstNode n, int index) {
- result = getStmtChild0(n, index)
- or
- result = getExprChild0(n, index)
- }
-
- private AstNode getParent(AstNode n) { n = getChild(result, _) }
-
- Callable getEnclosingCallable(AstNode node) {
- result = node.(ControlFlowElement).getEnclosingCallable() or
- result.(ObjectInitMethod).initializes(getParent*(node)) or
- Initializers::staticMemberInitializer(result, getParent*(node))
- }
-
- class Callable = CS::Callable;
-
- AstNode callableGetBody(Callable c) {
- not skipControlFlow(result) and
- result = c.getBody()
- }
-
- class Stmt = CS::Stmt;
-
- class Expr = CS::Expr;
-
- class BlockStmt = CS::BlockStmt;
-
- class ExprStmt = CS::ExprStmt;
-
- class IfStmt = CS::IfStmt;
-
- class LoopStmt = CS::LoopStmt;
-
- class WhileStmt = CS::WhileStmt;
-
- class DoStmt = CS::DoStmt;
-
- final private class FinalForStmt = CS::ForStmt;
-
- class ForStmt extends FinalForStmt {
- Expr getInit(int index) { result = this.getInitializer(index) }
- }
-
- final private class FinalForeachStmt = CS::ForeachStmt;
-
- class ForeachStmt extends FinalForeachStmt {
- Expr getVariable() {
- result = this.getVariableDeclExpr() or result = this.getVariableDeclTuple()
- }
-
- Expr getCollection() { result = this.getIterableExpr() }
- }
-
- class BreakStmt = CS::BreakStmt;
-
- class ContinueStmt = CS::ContinueStmt;
-
- class GotoStmt = CS::GotoStmt;
-
- class ReturnStmt = CS::ReturnStmt;
-
- class Throw = CS::ThrowElement;
-
- final private class FinalTryStmt = CS::TryStmt;
-
- class TryStmt extends FinalTryStmt {
- Stmt getBody() { result = this.getBlock() }
-
- CatchClause getCatch(int index) { result = this.getCatchClause(index) }
-
- Stmt getFinally() { result = super.getFinally() }
- }
-
- final private class FinalCatchClause = CS::CatchClause;
-
- class CatchClause extends FinalCatchClause {
- AstNode getVariable() { result = this.(CS::SpecificCatchClause).getVariableDeclExpr() }
-
- Expr getCondition() { result = this.getFilterClause() }
-
- Stmt getBody() { result = this.getBlock() }
- }
-
- final private class FinalSwitch = CS::Switch;
-
- class Switch extends FinalSwitch {
- Case getCase(int index) { result = super.getCase(index) }
-
- Stmt getStmt(int index) { result = this.(CS::SwitchStmt).getStmt(index) }
- }
-
- final private class FinalCase = CS::Case;
-
- class Case extends FinalCase {
- AstNode getAPattern() { result = this.getPattern() }
-
- Expr getGuard() { result = this.getCondition() }
-
- AstNode getBody() { result = super.getBody() }
- }
-
- class DefaultCase extends Case instanceof CS::DefaultCase { }
-
- class ConditionalExpr = CS::ConditionalExpr;
-
- class BinaryExpr = CS::BinaryOperation;
-
- class LogicalAndExpr = CS::LogicalAndExpr;
-
- class LogicalOrExpr = CS::LogicalOrExpr;
-
- class NullCoalescingExpr = CS::NullCoalescingExpr;
-
- class UnaryExpr = CS::UnaryOperation;
-
- class LogicalNotExpr = CS::LogicalNotExpr;
-
- class Assignment = CS::Assignment;
-
- class AssignExpr = CS::AssignExpr;
-
- class CompoundAssignment = CS::AssignOperation;
-
- class AssignLogicalAndExpr extends CompoundAssignment {
- AssignLogicalAndExpr() { none() }
- }
-
- class AssignLogicalOrExpr extends CompoundAssignment {
- AssignLogicalOrExpr() { none() }
- }
-
- class AssignNullCoalescingExpr = CS::AssignCoalesceExpr;
-
- final private class FinalBoolLiteral = CS::BoolLiteral;
-
- class BooleanLiteral extends FinalBoolLiteral {
- boolean getValue() { result = this.getBoolValue() }
- }
-
- final private class FinalIsExpr = CS::IsExpr;
-
- class PatternMatchExpr extends FinalIsExpr {
- AstNode getPattern() { result = super.getPattern() }
- }
-}
-
/**
* A compilation.
*
@@ -232,79 +41,17 @@ private class CompilationExt extends TCompilationExt {
}
/** Gets the compilation that source file `f` belongs to. */
-private CompilationExt getCompilation(File f) {
+bindingset[e]
+pragma[inline_late]
+private CompilationExt getCompilation(Element e) {
exists(Compilation c |
- f = c.getAFileCompiled() and
+ e.getALocation().getFile() = c.getAFileCompiled() and
result = TCompilation(c)
)
or
result = TBuildless()
}
-private module Initializers {
- private import semmle.code.csharp.ExprOrStmtParent as ExprOrStmtParent
-
- /**
- * The `expr_parent_top_level_adjusted()` relation restricted to exclude relations
- * between properties and their getters' expression bodies in properties such as
- * `int P => 0`.
- *
- * This is in order to only associate the expression body with one CFG scope, namely
- * the getter (and not the declaration itself).
- */
- private predicate expr_parent_top_level_adjusted2(
- Expr child, int i, @top_level_exprorstmt_parent parent
- ) {
- ExprOrStmtParent::expr_parent_top_level_adjusted(child, i, parent) and
- not exists(Getter g |
- g.getDeclaration() = parent and
- i = 0
- )
- }
-
- /**
- * Holds if `init` is a static member initializer and `staticCtor` is the
- * static constructor in the same declaring type. Hence, `staticCtor` can be
- * considered to execute `init` prior to the execution of its body.
- */
- predicate staticMemberInitializer(Constructor staticCtor, Expr init) {
- exists(Assignable a |
- a.(Modifiable).isStatic() and
- expr_parent_top_level_adjusted2(init, _, a) and
- a.getDeclaringType() = staticCtor.getDeclaringType() and
- staticCtor.isStatic()
- )
- }
-
- /**
- * Gets the `i`th static member initializer expression for static constructor `staticCtor`.
- */
- Expr initializedStaticMemberOrder(Constructor staticCtor, int i) {
- result =
- rank[i + 1](Expr init, Location l, string filepath, int startline, int startcolumn |
- staticMemberInitializer(staticCtor, init) and
- l = init.getLocation() and
- l.hasLocationInfo(filepath, startline, startcolumn, _, _)
- |
- init order by startline, startcolumn, filepath
- )
- }
-
- /**
- * Gets the `i`th member initializer expression for object initializer method `obinit`.
- */
- AssignExpr initializedInstanceMemberOrder(ObjectInitMethod obinit, int i) {
- result =
- rank[i + 1](AssignExpr ae0, Location l, string filepath, int startline, int startcolumn |
- obinit.initializes(ae0) and
- l = ae0.getLocation() and
- l.hasLocationInfo(filepath, startline, startcolumn, _, _)
- |
- ae0 order by startline, startcolumn, filepath
- )
- }
-}
-
private module Exceptions {
private import semmle.code.csharp.commons.Assertions
@@ -415,12 +162,12 @@ private module Input implements InputSig1, InputSig2 {
l = TLblGoto(n.(LabelStmt).getLabel())
}
- class CallableBodyPartContext = CompilationExt;
+ class CallableContext = CompilationExt;
pragma[nomagic]
- Ast::AstNode callableGetBodyPart(Callable c, CallableBodyPartContext ctx, int index) {
+ Ast::AstNode callableGetBodyPart(Ast::Callable c, CallableContext ctx, int index) {
not Ast::skipControlFlow(result) and
- ctx = getCompilation(result.getFile()) and
+ ctx = getCompilation(result) and
(
result = Initializers::initializedInstanceMemberOrder(c, index)
or
@@ -437,9 +184,19 @@ private module Input implements InputSig1, InputSig2 {
or
i = 2 and result = ctor.getBody()
)
+ or
+ not c instanceof Constructor and
+ result = c.getBody() and
+ index = 0
)
}
+ pragma[nomagic]
+ Ast::Parameter callableGetParameter(Ast::Callable c, CallableContext ctx, int index) {
+ result = Ast::callableGetParameter(c, index) and
+ ctx = getCompilation(result)
+ }
+
private Expr getQualifier(QualifiableExpr qe) {
result = qe.getQualifier() or
result = qe.(ExtensionMethodCall).getArgument(0)
diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowReachability.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowReachability.qll
index 33d96a61fc7e..4ec4dad9e1be 100644
--- a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowReachability.qll
+++ b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowReachability.qll
@@ -26,17 +26,7 @@ private module ControlFlowInput implements InputSig;
class GuardValue = GuardsImpl::GuardValue;
private module LogicInput implements GuardsImpl::LogicInputSig {
- class SsaDefinition extends Ssa::Definition {
- Expr getARead() { super.getARead() = result }
- }
-
- class SsaExplicitWrite extends SsaDefinition instanceof Ssa::ExplicitDefinition {
- Expr getValue() { result = super.getADefinition().getSource() }
- }
-
- class SsaPhiDefinition extends SsaDefinition instanceof Ssa::PhiNode {
- predicate hasInputFromBlock(SsaDefinition inp, BasicBlock bb) {
- super.hasInputFromBlock(inp, bb)
- }
- }
-
- class SsaParameterInit extends SsaDefinition instanceof Ssa::ImplicitParameterDefinition {
- Parameter getParameter() { result = super.getParameter() }
- }
+ import Ssa
predicate additionalNullCheck(GuardsImpl::PreGuard guard, GuardValue val, Expr e, boolean isNull) {
// Comparison with a non-`null` value, for example `x?.Length > 0`
@@ -586,7 +570,7 @@ class AccessOrCallExpr extends Expr {
* An expression can have more than one SSA qualifier in the presence
* of control flow splitting.
*/
- Ssa::Definition getAnSsaQualifier(ControlFlowNode cfn) { result = getAnSsaQualifier(this, cfn) }
+ SsaDefinition getAnSsaQualifier(ControlFlowNode cfn) { result = getAnSsaQualifier(this, cfn) }
}
private Declaration getDeclarationTarget(Expr e) {
@@ -594,22 +578,22 @@ private Declaration getDeclarationTarget(Expr e) {
result = e.(Call).getTarget()
}
-private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlowNode cfn) {
+private SsaDefinition getAnSsaQualifier(Expr e, ControlFlowNode cfn) {
e = getATrackedAccess(result, cfn)
or
not e = getATrackedAccess(_, _) and
result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier(), cfn)
}
-private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlowNode cfn) {
- result = def.getAReadAtNode(cfn)
+private AssignableAccess getATrackedAccess(SsaDefinition def, ControlFlowNode cfn) {
+ result = def.getARead() and cfn = result.getControlFlowNode()
or
- result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and
+ result = def.(SsaExplicitWrite).getDefinition().getTargetAccess() and
cfn = def.getControlFlowNode()
}
private predicate ssaMustHaveValue(Expr e, GuardValue v) {
- exists(Ssa::Definition def, BasicBlock bb |
+ exists(SsaDefinition def, BasicBlock bb |
e = def.getARead() and
e.getBasicBlock() = bb and
Guards::ssaControls(def, bb, v)
@@ -841,14 +825,12 @@ module Internal {
)
or
e =
- any(Ssa::Definition def |
- forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nullDef(u))
+ any(SsaDefinition def |
+ forex(SsaDefinition u | u = def.getAnUltimateDefinition() | nullDef(u))
).getARead()
}
- private predicate nullDef(Ssa::ExplicitDefinition def) {
- nullValueImplied(def.getADefinition().getSource())
- }
+ private predicate nullDef(SsaExplicitWrite def) { nullValueImplied(def.getValue()) }
predicate nonNullValueImplied(Expr e) {
nonNullValue(e)
@@ -856,14 +838,12 @@ module Internal {
exists(Expr e1 | nonNullValueImplied(e1) and nonNullValueImpliedUnary(e1, e))
or
e =
- any(Ssa::Definition def |
- forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
+ any(SsaDefinition def |
+ forex(SsaDefinition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
).getARead()
}
- private predicate nonNullDef(Ssa::ExplicitDefinition def) {
- nonNullValueImplied(def.getADefinition().getSource())
- }
+ private predicate nonNullDef(SsaExplicitWrite def) { nonNullValueImplied(def.getValue()) }
/** A callable that always returns a non-`null` value. */
private class NonNullCallable extends Callable {
@@ -1120,7 +1100,7 @@ module Internal {
private predicate nodeIsGuardedBySameSubExprSsaDef0(
ControlFlowNode cfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
ControlFlowNode subCfn, BasicBlock subCfnBB, AccessOrCallExpr sub, GuardValue v,
- Ssa::Definition def
+ SsaDefinition def
) {
nodeIsGuardedBySameSubExpr(cfn, guardedBB, guarded, g, sub, v) and
def = sub.getAnSsaQualifier(subCfn) and
@@ -1130,7 +1110,7 @@ module Internal {
pragma[nomagic]
private predicate nodeIsGuardedBySameSubExprSsaDef(
ControlFlowNode guardedCfn, AccessOrCallExpr guarded, Guard g, ControlFlowNode subCfn,
- AccessOrCallExpr sub, GuardValue v, Ssa::Definition def
+ AccessOrCallExpr sub, GuardValue v, SsaDefinition def
) {
exists(BasicBlock guardedBB, BasicBlock subCfnBB |
nodeIsGuardedBySameSubExprSsaDef0(guardedCfn, guardedBB, guarded, g, subCfn, subCfnBB, sub,
@@ -1149,7 +1129,7 @@ module Internal {
cached
predicate isGuardedByExpr(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, GuardValue v) {
isGuardedByExpr0(guarded, g, sub, v) and
- forall(ControlFlowNode subCfn, Ssa::Definition def |
+ forall(ControlFlowNode subCfn, SsaDefinition def |
nodeIsGuardedBySameSubExprSsaDef(_, guarded, g, subCfn, sub, v, def)
|
def = guarded.getAnSsaQualifier(_)
@@ -1161,7 +1141,7 @@ module Internal {
ControlFlowNodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, GuardValue v
) {
nodeIsGuardedBySameSubExpr(guarded, _, _, g, sub, v) and
- forall(ControlFlowNode subCfn, Ssa::Definition def |
+ forall(ControlFlowNode subCfn, SsaDefinition def |
nodeIsGuardedBySameSubExprSsaDef(guarded, _, g, subCfn, sub, v, def)
|
def =
diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll
new file mode 100644
index 000000000000..ca71e213e327
--- /dev/null
+++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll
@@ -0,0 +1,282 @@
+import csharp
+import codeql.controlflow.ControlFlowGraph
+
+module Initializers {
+ private import semmle.code.csharp.ExprOrStmtParent as ExprOrStmtParent
+
+ /**
+ * The `expr_parent_top_level_adjusted()` relation restricted to exclude relations
+ * between properties and their getters' expression bodies in properties such as
+ * `int P => 0`.
+ *
+ * This is in order to only associate the expression body with one CFG scope, namely
+ * the getter (and not the declaration itself).
+ */
+ private predicate expr_parent_top_level_adjusted2(
+ Expr child, int i, @top_level_exprorstmt_parent parent
+ ) {
+ ExprOrStmtParent::expr_parent_top_level_adjusted(child, i, parent) and
+ not exists(Getter g |
+ g.getDeclaration() = parent and
+ i = 0
+ )
+ }
+
+ /**
+ * Holds if `init` is a static member initializer and `staticCtor` is the
+ * static constructor in the same declaring type. Hence, `staticCtor` can be
+ * considered to execute `init` prior to the execution of its body.
+ */
+ predicate staticMemberInitializer(Constructor staticCtor, Expr init) {
+ exists(Assignable a |
+ a.(Modifiable).isStatic() and
+ expr_parent_top_level_adjusted2(init, _, a) and
+ a.getDeclaringType() = staticCtor.getDeclaringType() and
+ staticCtor.isStatic()
+ )
+ }
+
+ /**
+ * Gets the `i`th static member initializer expression for static constructor `staticCtor`.
+ */
+ Expr initializedStaticMemberOrder(Constructor staticCtor, int i) {
+ result =
+ rank[i + 1](Expr init, Location l, string filepath, int startline, int startcolumn |
+ staticMemberInitializer(staticCtor, init) and
+ l = init.getLocation() and
+ l.hasLocationInfo(filepath, startline, startcolumn, _, _)
+ |
+ init order by startline, startcolumn, filepath
+ )
+ }
+
+ /**
+ * Gets the `i`th member initializer expression for object initializer method `obinit`.
+ */
+ AssignExpr initializedInstanceMemberOrder(ObjectInitMethod obinit, int i) {
+ result =
+ rank[i + 1](AssignExpr ae0, Location l, string filepath, int startline, int startcolumn |
+ obinit.initializes(ae0) and
+ l = ae0.getLocation() and
+ l.hasLocationInfo(filepath, startline, startcolumn, _, _)
+ |
+ ae0 order by startline, startcolumn, filepath
+ )
+ }
+}
+
+/**
+ * Provides an implementation of the AST signature for C#.
+ */
+module Ast implements AstSig {
+ private import csharp as CS
+
+ class AstNode = ControlFlowElementOrCallable;
+
+ additional predicate skipControlFlow(AstNode e) {
+ e instanceof TypeAccess and
+ not e instanceof TypeAccessPatternExpr
+ or
+ not e.getFile().fromSource()
+ }
+
+ private AstNode getExprChild0(Expr e, int i) {
+ not e instanceof NameOfExpr and
+ not e instanceof AnonymousFunctionExpr and
+ not skipControlFlow(result) and
+ result = e.getChild(i)
+ }
+
+ private AstNode getStmtChild0(Stmt s, int i) {
+ not s instanceof FixedStmt and
+ not s instanceof UsingBlockStmt and
+ result = s.getChild(i)
+ or
+ s =
+ any(FixedStmt fs |
+ result = fs.getVariableDeclExpr(i)
+ or
+ result = fs.getBody() and
+ i = max(int j | exists(fs.getVariableDeclExpr(j))) + 1
+ )
+ or
+ s =
+ any(UsingBlockStmt us |
+ result = us.getExpr() and
+ i = 0
+ or
+ result = us.getVariableDeclExpr(i)
+ or
+ result = us.getBody() and
+ i = max([1, count(us.getVariableDeclExpr(_))])
+ )
+ }
+
+ AstNode getChild(AstNode n, int index) {
+ result = getStmtChild0(n, index)
+ or
+ result = getExprChild0(n, index)
+ }
+
+ private AstNode getParent(AstNode n) { n = getChild(result, _) }
+
+ Callable getEnclosingCallable(AstNode node) {
+ result = node.(ControlFlowElement).getEnclosingCallable()
+ or
+ result.(ObjectInitMethod).initializes(getParent*(node))
+ or
+ Initializers::staticMemberInitializer(result, getParent*(node))
+ or
+ result = node.(Parameter).getCallable()
+ or
+ not skipControlFlow(node) and
+ getParent*(node) = any(Parameter p | result = p.getCallable()).getDefaultValue()
+ }
+
+ class Callable extends CS::Callable {
+ Callable() { this.isUnboundDeclaration() }
+ }
+
+ AstNode callableGetBody(Callable c) {
+ not skipControlFlow(result) and
+ result = c.getBody()
+ }
+
+ final private class ParameterFinal = CS::Parameter;
+
+ class Parameter extends ParameterFinal {
+ Expr getDefaultValue() {
+ // Avoid combinatorial explosions for callables with multiple bodies
+ result = unique( | | super.getDefaultValue())
+ }
+ }
+
+ Parameter callableGetParameter(Callable c, int i) {
+ not skipControlFlow(result) and
+ result = c.getParameter(i)
+ }
+
+ class Stmt = CS::Stmt;
+
+ class Expr = CS::Expr;
+
+ class BlockStmt = CS::BlockStmt;
+
+ class ExprStmt = CS::ExprStmt;
+
+ class IfStmt = CS::IfStmt;
+
+ class LoopStmt = CS::LoopStmt;
+
+ class WhileStmt = CS::WhileStmt;
+
+ class DoStmt = CS::DoStmt;
+
+ final private class FinalForStmt = CS::ForStmt;
+
+ class ForStmt extends FinalForStmt {
+ Expr getInit(int index) { result = this.getInitializer(index) }
+ }
+
+ final private class FinalForeachStmt = CS::ForeachStmt;
+
+ class ForeachStmt extends FinalForeachStmt {
+ Expr getVariable() {
+ result = this.getVariableDeclExpr() or result = this.getVariableDeclTuple()
+ }
+
+ Expr getCollection() { result = this.getIterableExpr() }
+ }
+
+ class BreakStmt = CS::BreakStmt;
+
+ class ContinueStmt = CS::ContinueStmt;
+
+ class GotoStmt = CS::GotoStmt;
+
+ class ReturnStmt = CS::ReturnStmt;
+
+ class Throw = CS::ThrowElement;
+
+ final private class FinalTryStmt = CS::TryStmt;
+
+ class TryStmt extends FinalTryStmt {
+ Stmt getBody() { result = this.getBlock() }
+
+ CatchClause getCatch(int index) { result = this.getCatchClause(index) }
+
+ Stmt getFinally() { result = super.getFinally() }
+ }
+
+ final private class FinalCatchClause = CS::CatchClause;
+
+ class CatchClause extends FinalCatchClause {
+ AstNode getVariable() { result = this.(CS::SpecificCatchClause).getVariableDeclExpr() }
+
+ Expr getCondition() { result = this.getFilterClause() }
+
+ Stmt getBody() { result = this.getBlock() }
+ }
+
+ final private class FinalSwitch = CS::Switch;
+
+ class Switch extends FinalSwitch {
+ Case getCase(int index) { result = super.getCase(index) }
+
+ Stmt getStmt(int index) { result = this.(CS::SwitchStmt).getStmt(index) }
+ }
+
+ final private class FinalCase = CS::Case;
+
+ class Case extends FinalCase {
+ AstNode getPattern(int index) { result = this.getPattern() and index = 0 }
+
+ Expr getGuard() { result = this.getCondition() }
+
+ AstNode getBody() { result = super.getBody() }
+ }
+
+ class DefaultCase extends Case instanceof CS::DefaultCase { }
+
+ class ConditionalExpr = CS::ConditionalExpr;
+
+ class BinaryExpr = CS::BinaryOperation;
+
+ class LogicalAndExpr = CS::LogicalAndExpr;
+
+ class LogicalOrExpr = CS::LogicalOrExpr;
+
+ class NullCoalescingExpr = CS::NullCoalescingExpr;
+
+ class UnaryExpr = CS::UnaryOperation;
+
+ class LogicalNotExpr = CS::LogicalNotExpr;
+
+ class Assignment = CS::Assignment;
+
+ class AssignExpr = CS::AssignExpr;
+
+ class CompoundAssignment = CS::AssignOperation;
+
+ class AssignLogicalAndExpr extends CompoundAssignment {
+ AssignLogicalAndExpr() { none() }
+ }
+
+ class AssignLogicalOrExpr extends CompoundAssignment {
+ AssignLogicalOrExpr() { none() }
+ }
+
+ class AssignNullCoalescingExpr = CS::AssignCoalesceExpr;
+
+ final private class FinalBoolLiteral = CS::BoolLiteral;
+
+ class BooleanLiteral extends FinalBoolLiteral {
+ boolean getValue() { result = this.getBoolValue() }
+ }
+
+ final private class FinalIsExpr = CS::IsExpr;
+
+ class PatternMatchExpr extends FinalIsExpr {
+ AstNode getPattern() { result = super.getPattern() }
+ }
+}
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll
index d36fb68b9155..1cd9c71acfc9 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll
@@ -67,8 +67,8 @@ class AlwaysNullExpr extends Expr {
exists(AlwaysNullExpr e1, AlwaysNullExpr e2 | G::Internal::nullValueImpliedBinary(e1, e2, this))
or
this =
- any(Ssa::Definition def |
- forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nullDef(u))
+ any(SsaDefinition def |
+ forex(SsaDefinition u | u = def.getAnUltimateDefinition() | nullDef(u))
).getARead()
or
exists(Callable target |
@@ -80,9 +80,7 @@ class AlwaysNullExpr extends Expr {
}
/** Holds if SSA definition `def` is always `null`. */
-private predicate nullDef(Ssa::ExplicitDefinition def) {
- def.getADefinition().getSource() instanceof AlwaysNullExpr
-}
+private predicate nullDef(SsaExplicitWrite def) { def.getValue() instanceof AlwaysNullExpr }
/** An expression that is never `null`. */
class NonNullExpr extends Expr {
@@ -94,8 +92,8 @@ class NonNullExpr extends Expr {
this instanceof G::NullGuardedExpr
or
this =
- any(Ssa::Definition def |
- forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
+ any(SsaDefinition def |
+ forex(SsaDefinition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
).getARead()
or
exists(Callable target |
@@ -108,10 +106,10 @@ class NonNullExpr extends Expr {
}
/** Holds if SSA definition `def` is never `null`. */
-private predicate nonNullDef(Ssa::ExplicitDefinition def) {
- def.getADefinition().getSource() instanceof NonNullExpr
+private predicate nonNullDef(SsaExplicitWrite def) {
+ def.getValue() instanceof NonNullExpr
or
- exists(AssignableDefinition ad | ad = def.getADefinition() |
+ exists(AssignableDefinition ad | ad = def.getDefinition() |
ad instanceof AssignableDefinitions::PatternDefinition
or
ad =
@@ -124,13 +122,11 @@ private predicate nonNullDef(Ssa::ExplicitDefinition def) {
}
/**
- * Holds if `node` is a dereference `d` of SSA definition `def`.
+ * Holds if `d` is a dereference of SSA definition `def`.
*/
-private predicate dereferenceAt(ControlFlowNode node, Ssa::Definition def, Dereference d) {
- d = def.getAReadAtNode(node)
-}
+private predicate dereferenceAt(SsaDefinition def, Dereference d) { d = def.getARead() }
-private predicate isMaybeNullArgument(Ssa::ImplicitParameterDefinition def, MaybeNullExpr arg) {
+private predicate isMaybeNullArgument(SsaParameterInit def, MaybeNullExpr arg) {
exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p |
p = def.getParameter()
|
@@ -181,18 +177,8 @@ private predicate hasMultipleParamsArguments(Call c) {
)
}
-private predicate isNullDefaultArgument(Ssa::ImplicitParameterDefinition def, AlwaysNullExpr arg) {
- exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p |
- p = def.getParameter()
- |
- p = pdef.getParameter().getUnboundDeclaration() and
- arg = p.getDefaultValue() and
- not arg.getEnclosingCallable().getEnclosingCallable*() instanceof TestMethod
- )
-}
-
/** Holds if `def` is an SSA definition that may be `null`. */
-private predicate defMaybeNull(Ssa::Definition def, ControlFlowNode node, string msg, Element reason) {
+private predicate defMaybeNull(SsaDefinition def, ControlFlowNode node, string msg, Element reason) {
not nonNullDef(def) and
(
// A variable compared to `null` might be `null`
@@ -200,10 +186,10 @@ private predicate defMaybeNull(Ssa::Definition def, ControlFlowNode node, string
de.guardSuggestsMaybeNull(reason) and
msg = "as suggested by $@ null check" and
node = def.getControlFlowNode() and
- not de = any(Ssa::PhiNode phi).getARead() and
+ not de = any(SsaPhiDefinition phi).getARead() and
// Don't use a check as reason if there is a `null` assignment
// or argument
- not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr and
+ not def.(SsaExplicitWrite).getValue() instanceof MaybeNullExpr and
not isMaybeNullArgument(def, _)
)
or
@@ -216,37 +202,33 @@ private predicate defMaybeNull(Ssa::Definition def, ControlFlowNode node, string
else msg = "because of $@ potential null argument"
)
or
- isNullDefaultArgument(def, reason) and
- node = def.getControlFlowNode() and
- msg = "because the parameter has a null default value"
- or
// If the source of a variable is `null` then the variable may be `null`
- exists(AssignableDefinition adef | adef = def.(Ssa::ExplicitDefinition).getADefinition() |
+ exists(AssignableDefinition adef | adef = def.(SsaExplicitWrite).getDefinition() |
adef.getSource() = maybeNullExpr(node.asExpr()) and
reason = adef.getExpr() and
msg = "because of $@ assignment"
)
or
// A variable of nullable type may be null
- exists(Dereference d | dereferenceAt(_, def, d) |
+ exists(Dereference d | dereferenceAt(def, d) |
node = def.getControlFlowNode() and
d.hasNullableType() and
- not def instanceof Ssa::PhiNode and
+ not def instanceof SsaPhiDefinition and
reason = def.getSourceVariable().getAssignable() and
msg = "because it has a nullable type"
)
)
}
-private Ssa::Definition getAPseudoInput(Ssa::Definition def) {
- result = def.(Ssa::PhiNode).getAnInput()
+private SsaDefinition getAPseudoInput(SsaDefinition def) {
+ result = def.(SsaPhiDefinition).getAnInput()
}
// `def.getAnUltimateDefinition()` includes inputs into uncertain
// definitions, but we only want inputs into pseudo nodes
-private Ssa::Definition getAnUltimateDefinition(Ssa::Definition def) {
+private SsaDefinition getAnUltimateDefinition(SsaDefinition def) {
result = getAPseudoInput*(def) and
- not result instanceof Ssa::PhiNode
+ not result instanceof SsaPhiDefinition
}
/**
@@ -254,8 +236,8 @@ private Ssa::Definition getAnUltimateDefinition(Ssa::Definition def) {
* through an intermediate dereference that always throws a null reference
* exception.
*/
-private predicate defReaches(Ssa::Definition def, ControlFlowNode cfn) {
- exists(def.getAFirstReadAtNode(cfn))
+private predicate defReaches(SsaDefinition def, ControlFlowNode cfn) {
+ Ssa::ssaGetAFirstUse(def).getControlFlowNode() = cfn
or
exists(ControlFlowNode mid | defReaches(def, mid) |
SsaImpl::adjacentReadPairSameVar(_, mid, cfn) and
@@ -264,11 +246,12 @@ private predicate defReaches(Ssa::Definition def, ControlFlowNode cfn) {
}
private module NullnessConfig implements ControlFlowReachability::ConfigSig {
- predicate source(ControlFlowNode node, Ssa::Definition def) { defMaybeNull(def, node, _, _) }
+ predicate source(ControlFlowNode node, SsaDefinition def) { defMaybeNull(def, node, _, _) }
- predicate sink(ControlFlowNode node, Ssa::Definition def) {
+ predicate sink(ControlFlowNode node, SsaDefinition def) {
exists(Dereference d |
- dereferenceAt(node, def, d) and
+ dereferenceAt(def, d) and
+ node = d.getControlFlowNode() and
not d instanceof NonNullExpr
)
}
@@ -281,11 +264,12 @@ private module NullnessConfig implements ControlFlowReachability::ConfigSig {
private module NullnessFlow = ControlFlowReachability::Flow;
predicate maybeNullDeref(Dereference d, Ssa::SourceVariable v, string msg, Element reason) {
- exists(Ssa::Definition origin, Ssa::Definition ssa, ControlFlowNode src, ControlFlowNode sink |
+ exists(SsaDefinition origin, SsaDefinition ssa, ControlFlowNode src, ControlFlowNode sink |
defMaybeNull(origin, src, msg, reason) and
NullnessFlow::flow(src, origin, sink, ssa) and
ssa.getSourceVariable() = v and
- dereferenceAt(sink, ssa, d) and
+ dereferenceAt(ssa, d) and
+ sink = d.getControlFlowNode() and
not d.isAlwaysNull(v)
)
}
@@ -336,10 +320,7 @@ class Dereference extends G::DereferenceableExpr {
not p.getAnnotatedType().isNullableRefType()
or
p.fromSource() and
- exists(
- Ssa::ImplicitParameterDefinition def,
- AssignableDefinitions::ImplicitParameterDefinition pdef
- |
+ exists(SsaParameterInit def, AssignableDefinitions::ImplicitParameterDefinition pdef |
p = def.getParameter()
|
p.getUnboundDeclaration() = pdef.getParameter() and
@@ -349,9 +330,9 @@ class Dereference extends G::DereferenceableExpr {
)
}
- private predicate isAlwaysNull0(Ssa::Definition def) {
- forall(Ssa::Definition input | input = getAnUltimateDefinition(def) |
- input.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof AlwaysNullExpr
+ private predicate isAlwaysNull0(SsaDefinition def) {
+ forall(SsaDefinition input | input = getAnUltimateDefinition(def) |
+ input.(SsaExplicitWrite).getValue() instanceof AlwaysNullExpr
) and
not nonNullDef(def) and
this = def.getARead() and
@@ -367,7 +348,7 @@ class Dereference extends G::DereferenceableExpr {
// Exclude fields and properties, as they may not have an accurate SSA representation
v.getAssignable() instanceof LocalScopeVariable and
(
- forex(Ssa::Definition def0 | this = def0.getARead() | this.isAlwaysNull0(def0))
+ forex(SsaDefinition def0 | this = def0.getARead() | this.isAlwaysNull0(def0))
or
exists(G::GuardValue nv |
this.(G::GuardedExpr).mustHaveValue(nv) and
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
index 92149e026405..fee6bedf0f3e 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
@@ -3,13 +3,14 @@
*/
import csharp
+private import internal.SsaImpl as SsaImpl
+import SsaImpl::Ssa_
/**
* Provides classes for working with static single assignment (SSA) form.
*/
module Ssa {
- private import internal.SsaImpl as SsaImpl
- private import semmle.code.csharp.internal.Location
+ import SsaImpl::Ssa_
pragma[nomagic]
private predicate assignableDefinitionLocalScopeVariable(
@@ -19,15 +20,6 @@ module Ssa {
ad.getEnclosingCallable() = c
}
- pragma[nomagic]
- private predicate localScopeSourceVariable(
- SourceVariables::LocalScopeSourceVariable sv, LocalScopeVariable v, Callable c1, Callable c2
- ) {
- sv.getAssignable() = v and
- sv.getEnclosingCallable() = c1 and
- v.getCallable() = c2
- }
-
/**
* A variable that can be SSA converted.
*
@@ -54,7 +46,7 @@ module Ssa {
not exists(result.getTargetAccess()) and
exists(LocalScopeVariable v, Callable c |
assignableDefinitionLocalScopeVariable(result, v, c) and
- localScopeSourceVariable(this, v, c, _)
+ SsaImpl::localScopeSourceVariable(this, v, c, _)
)
}
@@ -82,7 +74,7 @@ module Ssa {
* Gets an SSA definition that has this variable as its underlying
* source variable.
*/
- Definition getAnSsaDefinition() { result.getSourceVariable() = this }
+ SsaDefinition getAnSsaDefinition() { result.getSourceVariable() = this }
}
/** Provides different types of `SourceVariable`s. */
@@ -158,11 +150,49 @@ module Ssa {
}
/**
+ * Gets a read of the source variable underlying the SSA definition `def`
+ * that can be reached from `def` without passing through any
+ * other SSA definition or read. Example:
+ *
+ * ```csharp
+ * int Field;
+ *
+ * void SetField(int i) {
+ * this.Field = i;
+ * Use(this.Field);
+ * if (i > 0)
+ * this.Field = i - 1;
+ * else if (i < 0)
+ * SetField(1);
+ * Use(this.Field);
+ * Use(this.Field);
+ * }
+ * ```
+ *
+ * - The read of `i` on line 4 can be reached from the explicit SSA
+ * definition (wrapping an implicit entry definition) on line 3.
+ * - The reads of `i` on lines 6 and 7 are not the first reads of any SSA
+ * definition.
+ * - The read of `this.Field` on line 5 can be reached from the explicit SSA
+ * definition on line 4.
+ * - The read of `this.Field` on line 10 can be reached from the phi node
+ * between lines 9 and 10.
+ * - The read of `this.Field` on line 11 is not the first read of any SSA
+ * definition.
+ *
+ * Subsequent reads can be found by following the steps defined by
+ * `AssignableRead.getANextRead()`.
+ */
+ AssignableRead ssaGetAFirstUse(SsaDefinition def) { SsaImpl::firstReadSameVar(def, result) }
+
+ /**
+ * DEPRECATED: Use `SsaDefinition` instead.
+ *
* A static single assignment (SSA) definition. Either an explicit variable
* definition (`ExplicitDefinition`), an implicit variable definition
* (`ImplicitDefinition`), or a phi node (`PhiNode`).
*/
- class Definition extends SsaImpl::Definition {
+ deprecated class Definition extends SsaImpl::Definition {
/** Gets the control flow node of this SSA definition. */
final ControlFlowNode getControlFlowNode() {
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(0.maximum(i)))
@@ -203,9 +233,11 @@ module Ssa {
* - The reads of `this.Field` on lines 10 and 11 can be reached from the phi
* node between lines 9 and 10.
*/
- final AssignableRead getARead() { result = this.getAReadAtNode(_) }
+ final AssignableRead getARead() { result = SsaImpl::getAReadAtNode(this, _) }
/**
+ * DEPRECATED: Use `getARead()` instead.
+ *
* Gets a read of the source variable underlying this SSA definition at
* control flow node `cfn` that can be reached from this SSA definition
* without passing through any other SSA definitions. Example:
@@ -232,11 +264,13 @@ module Ssa {
* - The reads of `this.Field` on lines 10 and 11 can be reached from the phi
* node between lines 9 and 10.
*/
- final AssignableRead getAReadAtNode(ControlFlowNode cfn) {
+ deprecated final AssignableRead getAReadAtNode(ControlFlowNode cfn) {
result = SsaImpl::getAReadAtNode(this, cfn)
}
/**
+ * DEPRECATED: Use `ssaGetAFirstUse` instead.
+ *
* Gets a read of the source variable underlying this SSA definition that
* can be reached from this SSA definition without passing through any
* other SSA definition or read. Example:
@@ -270,9 +304,11 @@ module Ssa {
* Subsequent reads can be found by following the steps defined by
* `AssignableRead.getANextRead()`.
*/
- final AssignableRead getAFirstRead() { result = this.getAFirstReadAtNode(_) }
+ deprecated final AssignableRead getAFirstRead() { result = this.getAFirstReadAtNode(_) }
/**
+ * DEPRECATED: Use `ssaGetAFirstUse` instead.
+ *
* Gets a read of the source variable underlying this SSA definition at
* control flow node `cfn` that can be reached from this SSA definition
* without passing through any other SSA definition or read. Example:
@@ -306,8 +342,8 @@ module Ssa {
* Subsequent reads can be found by following the steps defined by
* `AssignableRead.getANextRead()`.
*/
- final AssignableRead getAFirstReadAtNode(ControlFlowNode cfn) {
- SsaImpl::firstReadSameVar(this, cfn) and
+ deprecated final AssignableRead getAFirstReadAtNode(ControlFlowNode cfn) {
+ SsaImpl::firstReadSameVar(this, result) and
result.getControlFlowNode() = cfn
}
@@ -316,8 +352,8 @@ module Ssa {
* includes inputs to phi nodes and the prior definitions of uncertain writes.
*/
private Definition getAPhiInputOrPriorDefinition() {
- result = this.(PhiNode).getAnInput() or
- result = this.(UncertainDefinition).getPriorDefinition()
+ result = this.(SsaPhiDefinition).getAnInput() or
+ result = this.(SsaUncertainWrite).getPriorDefinition()
}
/**
@@ -351,7 +387,7 @@ module Ssa {
*/
final Definition getAnUltimateDefinition() {
result = this.getAPhiInputOrPriorDefinition*() and
- not result instanceof PhiNode
+ not result instanceof SsaPhiDefinition
}
/**
@@ -363,37 +399,46 @@ module Ssa {
result.(ControlFlowElement).getControlFlowNode() = this.getControlFlowNode()
}
- /** Gets the callable to which this SSA definition belongs. */
- final Callable getEnclosingCallable() {
+ /**
+ * DEPRECATED: Use `getSourceVariable().getEnclosingCallable()` instead.
+ *
+ * Gets the callable to which this SSA definition belongs.
+ */
+ deprecated final Callable getEnclosingCallable() {
result = this.getSourceVariable().getEnclosingCallable()
}
/**
+ * DEPRECATED.
+ *
* Holds if this SSA definition assigns to `out`/`ref` parameter `p`, and the
* parameter may remain unchanged throughout the rest of the enclosing callable.
*/
- final predicate isLiveOutRefParameterDefinition(Parameter p) {
+ deprecated final predicate isLiveOutRefParameterDefinition(Parameter p) {
SsaImpl::isLiveOutRefParameterDefinition(this, p)
}
-
- /** Gets the location of this SSA definition. */
- override Location getLocation() { none() }
}
/**
+ * DEPRECATED: Use `SsaExplicitWrite` instead.
+ *
* An SSA definition that corresponds to an explicit assignable definition.
*/
- class ExplicitDefinition extends Definition, SsaImpl::WriteDefinition {
+ deprecated class ExplicitDefinition extends Definition, SsaImpl::WriteDefinition {
AssignableDefinition ad;
ExplicitDefinition() { SsaImpl::explicitDefinition(this, _, ad) }
/**
+ * DEPRECATED: Use `SsaExplicitWrite.getDefinition()` instead.
+ *
* Gets an underlying assignable definition. The result is always unique,
* except for pathological `out`/`ref` assignments like `M(out x, out x)`,
* where there may be more than one underlying definition.
*/
- final AssignableDefinition getADefinition() { result = SsaImpl::getADefinition(this) }
+ deprecated final AssignableDefinition getADefinition() {
+ result = SsaImpl::getADefinition(this)
+ }
/**
* DEPRECATED.
@@ -454,20 +499,18 @@ module Ssa {
}
override Element getElement() { result = ad.getElement() }
-
- override string toString() { result = "SSA def(" + this.getSourceVariable() + ")" }
-
- override Location getLocation() { result = ad.getLocation() }
}
/**
+ * DEPRECATED: Use `SsaParameterInit` or `SsaImplicitWrite` instead.
+ *
* An SSA definition that does not correspond to an explicit variable definition.
* Either an implicit initialization of a variable at the beginning of a callable
* (`ImplicitEntryDefinition`), an implicit definition via a call
* (`ImplicitCallDefinition`), or an implicit definition where the qualifier is
* updated (`ImplicitQualifierDefinition`).
*/
- class ImplicitDefinition extends Definition, SsaImpl::WriteDefinition {
+ deprecated class ImplicitDefinition extends Definition, SsaImpl::WriteDefinition {
ImplicitDefinition() {
exists(BasicBlock bb, SourceVariable v, int i | this.definesAt(v, bb, i) |
SsaImpl::implicitEntryDefinition(bb, v) and
@@ -481,11 +524,13 @@ module Ssa {
}
/**
+ * DEPRECATED: Use `SsaParameterInit` or `SsaImplicitEntryDefinition` instead.
+ *
* An SSA definition representing the implicit initialization of a variable
- * at the beginning of a callable. Either a parameter, a local scope variable
- * captured by the callable, or a field or property accessed inside the callable.
+ * at the beginning of a callable. Either a local scope variable captured by
+ * the callable or a field or property accessed inside the callable.
*/
- class ImplicitEntryDefinition extends ImplicitDefinition {
+ deprecated class ImplicitEntryDefinition extends ImplicitDefinition {
ImplicitEntryDefinition() {
exists(BasicBlock bb, SourceVariable v |
this.definesAt(v, bb, -1) and
@@ -497,69 +542,40 @@ module Ssa {
final Callable getCallable() { result = this.getBasicBlock().getEnclosingCallable() }
override Element getElement() { result = this.getCallable() }
-
- override string toString() {
- if this.getSourceVariable().getAssignable() instanceof LocalScopeVariable
- then result = "SSA capture def(" + this.getSourceVariable() + ")"
- else result = "SSA entry def(" + this.getSourceVariable() + ")"
- }
-
- override Location getLocation() { result = this.getCallable().getLocation() }
- }
-
- private module NearestLocationInput implements NearestLocationInputSig {
- class C = ImplicitParameterDefinition;
-
- predicate relevantLocations(ImplicitParameterDefinition def, Location l1, Location l2) {
- not def.getBasicBlock() instanceof EntryBasicBlock and
- l1 = def.getParameter().getALocation() and
- l2 = def.getBasicBlock().getLocation()
- }
- }
-
- pragma[nomagic]
- private predicate implicitEntryDef(ImplicitEntryDefinition def, SourceVariable v, Callable c) {
- v = def.getSourceVariable() and
- c = def.getCallable()
}
/**
- * An SSA definition representing the implicit initialization of a parameter
- * at the beginning of a callable.
+ * DEPRECATED: Use `SsaParameterInit` instead.
*/
- class ImplicitParameterDefinition extends ImplicitEntryDefinition {
+ deprecated final class ImplicitParameterDefinition = SsaImpl::ParameterDefinitionImpl;
+
+ deprecated private class ExplicitParameterDefinition extends ExplicitDefinition,
+ SsaImpl::ParameterDefinitionImpl
+ {
private Parameter p;
+ override AssignableDefinitions::ImplicitParameterDefinition ad;
- ImplicitParameterDefinition() {
- exists(SourceVariable sv, Callable c |
- implicitEntryDef(this, sv, c) and
- localScopeSourceVariable(sv, p, _, c)
- )
- }
+ ExplicitParameterDefinition() { p = ad.getParameter() }
- /** Gets the parameter that this entry definition represents. */
- Parameter getParameter() { result = p }
+ override Parameter getParameter() { result = p }
- override Element getElement() { result = this.getParameter() }
+ override string toString() { result = SsaImpl::ParameterDefinitionImpl.super.toString() }
+ }
- override string toString() {
- result = "SSA param(" + pragma[only_bind_out](this.getParameter()) + ")"
+ /** An SSA definition in a closure that captures a variable. */
+ class SsaCapturedDefinition extends SsaImplicitEntryDefinition {
+ SsaCapturedDefinition() {
+ this.getSourceVariable().getAssignable() instanceof LocalScopeVariable
}
- override Location getLocation() {
- not NearestLocation::nearestLocation(this, _, _) and
- result = p.getLocation()
- or
- // multi-bodied method: use matching parameter location
- NearestLocation::nearestLocation(this, result, _)
- }
+ override string toString() { result = "SSA capture def(" + this.getSourceVariable() + ")" }
}
/**
* An SSA definition representing the potential definition of a variable
* via a call.
*/
- class ImplicitCallDefinition extends ImplicitDefinition {
+ class ImplicitCallDefinition extends SsaImplicitWrite {
private Call c;
ImplicitCallDefinition() {
@@ -586,18 +602,17 @@ module Ssa {
}
override string toString() { result = "SSA call def(" + this.getSourceVariable() + ")" }
-
- override Location getLocation() { result = this.getCall().getLocation() }
}
/**
* An SSA definition representing the potential definition of a variable
* via an SSA definition for the qualifier.
*/
- class ImplicitQualifierDefinition extends ImplicitDefinition, SsaImpl::WriteDefinition {
- private Definition q;
+ class ImplicitQualifierDefinition extends SsaImplicitWrite {
+ private SsaDefinition q;
ImplicitQualifierDefinition() {
+ not this instanceof SsaImplicitEntryDefinition and
exists(BasicBlock bb, int i, SourceVariables::QualifiedFieldOrPropSourceVariable v |
this.definesAt(v, bb, i)
|
@@ -607,19 +622,19 @@ module Ssa {
}
/** Gets the SSA definition for the qualifier. */
- final Definition getQualifierDefinition() { result = q }
+ final SsaDefinition getQualifierDefinition() { result = q }
override string toString() { result = "SSA qualifier def(" + this.getSourceVariable() + ")" }
-
- override Location getLocation() { result = this.getQualifierDefinition().getLocation() }
}
/**
+ * DEPRECATED: Use `SsaPhiDefinition` instead.
+ *
* An SSA phi node, that is, a pseudo definition for a variable at a point
* in the flow graph where otherwise two or more definitions for the variable
* would be visible.
*/
- class PhiNode extends Definition, SsaImpl::PhiNode {
+ deprecated class PhiNode extends Definition, SsaImpl::PhiNode {
/**
* Gets an input of this phi node. Example:
*
@@ -648,27 +663,17 @@ module Ssa {
predicate hasInputFromBlock(Definition inp, BasicBlock bb) {
inp = SsaImpl::phiHasInputFromBlock(this, bb)
}
-
- override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" }
-
- /*
- * The location of a phi node is the same as the location of the first node
- * in the basic block in which it is defined.
- *
- * Strictly speaking, the node is *before* the first node, but such a location
- * does not exist in the source program.
- */
-
- override Location getLocation() { result = this.getBasicBlock().getFirstNode().getLocation() }
}
/**
+ * DEPRECATED: Use `SsaUncertainWrite` instead.
+ *
* An SSA definition that represents an uncertain update of the underlying
* assignable. Either an explicit update that is uncertain (`ref` assignments
* need not be certain), an implicit non-local update via a call, or an
* uncertain update of the qualifier.
*/
- class UncertainDefinition extends Definition, SsaImpl::UncertainWriteDefinition {
+ deprecated class UncertainDefinition extends Definition, SsaImpl::UncertainWriteDefinition {
/**
* Gets the immediately preceding definition. Since this update is uncertain,
* the value from the preceding definition might still be valid.
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll
index 63a9e782250f..0e879ac94123 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll
@@ -1,9 +1,20 @@
-import csharp
+private import csharp as CS
/**
* Provides a simple SSA implementation for local scope variables.
*/
module BaseSsa {
+ private import BaseSsaImpl
+
+ class SimpleLocalScopeVariable = BaseSsaImpl::SimpleLocalScopeVariable;
+
+ module Ssa = SsaImpl::MakeSsa;
+
+ import Ssa
+}
+
+private module BaseSsaImpl {
+ private import CS
private import AssignableDefinitions
private import codeql.ssa.Ssa as SsaImplCommon
@@ -13,7 +24,7 @@ module BaseSsa {
predicate ref() { any() }
cached
- predicate backref() { (exists(any(SsaDefinition def).getARead()) implies any()) }
+ predicate backref() { (exists(any(BaseSsa::SsaDefinition def).getARead()) implies any()) }
}
/**
@@ -112,11 +123,9 @@ module BaseSsa {
}
}
- private module SsaImpl = SsaImplCommon::Make;
-
- private module SsaInput implements SsaImpl::SsaInputSig {
- private import csharp as CS
+ module SsaImpl = SsaImplCommon::Make;
+ module SsaInput implements SsaImpl::SsaInputSig {
class Expr = CS::Expr;
class Parameter = CS::Parameter;
@@ -139,8 +148,4 @@ module BaseSsa {
w.isParameterInit(v)
}
}
-
- module Ssa = SsaImpl::MakeSsa;
-
- import Ssa
}
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
index 5b3bf5f2dae0..f0d4bd996214 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll
@@ -175,6 +175,18 @@ private module ThisFlow {
result = strictcount(int primaryParamPos | primaryConstructorThisAccess(_, bb, primaryParamPos))
}
+ private module BodyNearestLocationInput implements NearestLocationInputSig {
+ class C = ControlFlowElement;
+
+ predicate relevantLocations(ControlFlowElement body, Location l1, Location l2) {
+ exists(DataFlowCallable c |
+ any(InstanceParameterNode p).isParameterOf(c, _) and
+ body = c.asCallable(l1).getBody() and
+ l2 = body.getLocation()
+ )
+ }
+ }
+
private predicate thisAccess(Node n, BasicBlock bb, int i) {
thisAccess(n, bb.getNode(i))
or
@@ -183,21 +195,29 @@ private module ThisFlow {
i = ppos - numberOfPrimaryConstructorParameters(bb)
)
or
- exists(DataFlowCallable c, EntryBasicBlock entry |
- n.(InstanceParameterNode).isParameterOf(c, _) and
- exists(ControlFlowNode succ |
- succ = c.getAControlFlowNode() and
- succ = entry.getFirstNode().getASuccessor() and
+ exists(Callable c, InstanceParameterNode p, Location l |
+ p = n and
+ c = p.getCallable(l) and
+ (
// In case `c` has multiple bodies, we want each body to gets its own implicit
- // entry definition. In case `c` doesn't have multiple bodies, the line below
- // is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
- // will be in the entry block.
- bb = succ.getBasicBlock()
- |
- i = -1 - numberOfPrimaryConstructorParameters(bb)
+ // entry definition.
+ exists(ControlFlowElement body |
+ body = c.getBody() and
+ bb.getANode().isBefore(body) and
+ NearestLocation::nearestLocation(body, l, _)
+ )
or
- not exists(numberOfPrimaryConstructorParameters(bb)) and i = -1
+ not c.hasBody() and
+ exists(EntryBasicBlock entry, ControlFlowNode succ |
+ succ = p.getEnclosingCallableImpl().getAControlFlowNode() and
+ succ = entry.getFirstNode().getASuccessor() and
+ bb = succ.getBasicBlock()
+ )
)
+ |
+ i = -1 - numberOfPrimaryConstructorParameters(bb)
+ or
+ not exists(numberOfPrimaryConstructorParameters(bb)) and i = -1
)
}
@@ -250,10 +270,10 @@ module VariableCapture {
private predicate closureFlowStep(ControlFlowNodes::ExprNode e1, ControlFlowNodes::ExprNode e2) {
e1.getExpr() = LocalFlow::getALastEvalNode(e2.getExpr())
or
- exists(Ssa::Definition def, AssignableDefinition adef |
+ exists(SsaDefinition def, AssignableDefinition adef |
LocalFlow::defAssigns(adef, _, _, e1) and
- def.getAnUltimateDefinition().(Ssa::ExplicitDefinition).getADefinition() = adef and
- exists(def.getAReadAtNode(e2))
+ def.getAnUltimateDefinition().(SsaExplicitWrite).getDefinition() = adef and
+ def.getARead().getControlFlowNode() = e2
)
}
@@ -580,8 +600,8 @@ module LocalFlow {
or
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
- exists(AssignableDefinition def, ControlFlowNode cfn, Ssa::ExplicitDefinition ssaDef |
- ssaDef.getADefinition() = def and
+ exists(AssignableDefinition def, ControlFlowNode cfn, SsaExplicitWrite ssaDef |
+ ssaDef.getDefinition() = def and
ssaDef.getControlFlowNode() = cfn and
nodeFrom = TAssignableDefinitionNode(def, cfn) and
nodeTo.(SsaDefinitionNode).getDefinition() = ssaDef
@@ -918,8 +938,6 @@ private Gvn::GvnType getANonTypeParameterSubTypeRestricted(RelevantGvnType t) {
/** A callable with an implicit `this` parameter. */
private class InstanceCallable extends Callable {
- private Location l;
-
InstanceCallable() {
not this.(Modifiable).isStatic() and
// local functions and delegate capture `this` and should therefore
@@ -927,8 +945,6 @@ private class InstanceCallable extends Callable {
not this instanceof LocalFunction and
not this instanceof AnonymousFunctionExpr
}
-
- Location getARelevantLocation() { result = l }
}
/**
@@ -1019,8 +1035,7 @@ private module Cached {
} or
TInstanceParameterNode(InstanceCallable c, Location l) {
c = any(DataFlowCallable dfc).asCallable(l) and
- c instanceof CallableUsedInSource and
- l = c.getARelevantLocation()
+ c instanceof CallableUsedInSource
} or
TDelegateSelfReferenceNode(Callable c) { lambdaCreationExpr(_, c) } or
TLocalFunctionCreationNode(ControlFlowNodes::ElementNode cfn, Boolean isPostUpdate) {
@@ -1229,7 +1244,7 @@ class SsaNode extends NodeImpl, TSsaNode {
class SsaDefinitionNode extends SsaNode {
override SsaImpl::DataFlowIntegration::SsaDefinitionNode node;
- Ssa::Definition getDefinition() { result = node.getDefinition() }
+ SsaDefinition getDefinition() { result = node.getDefinition() }
override ControlFlowNode getControlFlowNodeImpl() {
result = this.getDefinition().getControlFlowNode()
@@ -1287,12 +1302,6 @@ private module NearestLocationInputParamAfterCallable implements NearestLocation
}
private module ParameterNodes {
- pragma[nomagic]
- private predicate ssaParamDef(Ssa::ImplicitParameterDefinition ssaDef, Parameter p, Location l) {
- p = ssaDef.getParameter() and
- l = ssaDef.getLocation()
- }
-
private module NearestLocationInputParamBeforeCallable implements NearestLocationInputSig {
class C = Parameter;
@@ -1343,11 +1352,9 @@ private module ParameterNodes {
}
/** Gets the SSA definition corresponding to this parameter, if any. */
- Ssa::ImplicitParameterDefinition getSsaDefinition() {
- exists(Parameter p, Location l |
- l = this.getParameterLocation(p) and
- ssaParamDef(result, p, l)
- )
+ SsaParameterInit getSsaDefinition() {
+ result.getParameter() = parameter and
+ result.getBasicBlock() = callable.getABasicBlock()
}
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
@@ -1423,7 +1430,7 @@ private module ParameterNodes {
}
/** An implicit entry definition for a captured variable. */
- class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition {
+ deprecated class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition {
private LocalScopeVariable v;
SsaCapturedEntryDefinition() { this.getSourceVariable().getAssignable() = v }
@@ -1598,7 +1605,7 @@ private module ReturnNodes {
OutRefReturnNode() {
exists(Parameter p |
- this.getDefinition().isLiveOutRefParameterDefinition(p) and
+ SsaImpl::isLiveOutRefParameterDefinition(this.getDefinition(), p) and
kind.getPosition() = p.getPosition()
|
p.isOut() and kind instanceof OutReturnKind
@@ -2001,12 +2008,9 @@ private class FieldOrPropertyRead extends FieldOrPropertyAccess, AssignableRead
* SSA updates.
*/
predicate hasNonlocalValue() {
- exists(Ssa::Definition def, Ssa::ImplicitDefinition idef |
+ exists(SsaDefinition def |
def.getARead() = this and
- idef = def.getAnUltimateDefinition()
- |
- idef instanceof Ssa::ImplicitEntryDefinition or
- idef instanceof Ssa::ImplicitCallDefinition
+ def.getAnUltimateDefinition() instanceof SsaImplicitWrite
)
}
}
@@ -2205,12 +2209,11 @@ private predicate readContentStep(Node node1, Content c, Node node2) {
c instanceof ElementContent
or
exists(
- ForeachStmt fs, Ssa::ExplicitDefinition def,
- AssignableDefinitions::LocalVariableDefinition defTo
+ ForeachStmt fs, SsaExplicitWrite def, AssignableDefinitions::LocalVariableDefinition defTo
|
node1.asExpr() = fs.getIterableExpr() and
defTo.getDeclaration() = fs.getVariableDeclExpr() and
- def.getADefinition() = defTo and
+ def.getDefinition() = defTo and
node2.(SsaDefinitionNode).getDefinition() = def and
c instanceof ElementContent
)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll
index 6e933c6a8e0c..b7257a2f5f2b 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll
@@ -7,8 +7,9 @@ private import codeql.ssa.Ssa as SsaImplCommon
private import AssignableDefinitions
private import semmle.code.csharp.controlflow.Guards as Guards
private import semmle.code.csharp.dataflow.internal.BaseSSA
+private import semmle.code.csharp.internal.Location
-private module SsaInput implements SsaImplCommon::InputSig {
+private module SsaImplInput implements SsaImplCommon::InputSig {
class SourceVariable = Ssa::SourceVariable;
/**
@@ -40,15 +41,52 @@ private module SsaInput implements SsaImplCommon::InputSig
}
}
-import SsaImplCommon::Make as Impl
+import SsaImplCommon::Make as Impl
+
+private module SsaInput implements Impl::SsaInputSig {
+ private import csharp as CS
+
+ class Expr = CS::Expr;
+
+ class Parameter = CS::Parameter;
+
+ class VariableWrite extends AssignableDefinition {
+ Expr asExpr() { result = this.getExpr() }
+
+ Expr getValue() { result = this.getSource() }
+
+ predicate isParameterInit(Parameter p) { this.(ImplicitParameterDefinition).getParameter() = p }
+ }
+
+ predicate explicitWrite(VariableWrite w, BasicBlock bb, int i, SsaImplInput::SourceVariable v) {
+ exists(AssignableDefinition ad | variableDefinition(bb, i, v, ad) |
+ w = ad or
+ w = getASameOutRefDefAfter(v, ad)
+ )
+ or
+ exists(Parameter p |
+ implicitEntryDefinition(bb, v) and
+ i = -1 and
+ p = v.getAssignable() and
+ pragma[only_bind_out](p.getCallable()) = pragma[only_bind_out](v.getEnclosingCallable()) and
+ w.isParameterInit(p)
+ )
+ }
+}
+
+module Ssa_ = Impl::MakeSsa;
class Definition = Impl::Definition;
-class WriteDefinition = Impl::WriteDefinition;
+private class SsaDefinitionToStringProxy extends Definition {
+ override string toString() { result = this.(SsaDefinition).toString() }
+}
+
+deprecated class WriteDefinition = Impl::WriteDefinition;
-class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
+deprecated class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
-class PhiNode = Impl::PhiNode;
+deprecated class PhiNode = Impl::PhiNode;
module Consistency = Impl::Consistency;
@@ -126,7 +164,6 @@ private module SourceVariableImpl {
*/
predicate variableDefinition(BasicBlock bb, int i, Ssa::SourceVariable v, AssignableDefinition ad) {
ad = v.getADefinition() and
- ad.getExpr().getControlFlowNode() = bb.getNode(i) and
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = ad |
second.getAssignment() = first.getAssignment() and
@@ -136,7 +173,13 @@ private module SourceVariableImpl {
// In cases like `M(out x, out x)`, there is no inherent evaluation order, so we
// collapse the two definitions of `x`, using the first access as the representative,
// and expose both definitions in `ExplicitDefinition.getADefinition()`
- not ad = getASameOutRefDefAfter(v, _)
+ not ad = getASameOutRefDefAfter(v, _) and
+ (
+ ad.getExpr().getControlFlowNode() = bb.getNode(i)
+ or
+ ad.(AssignableDefinitions::ImplicitParameterDefinition).getParameter().getControlFlowNode() =
+ bb.getNode(i)
+ )
}
/**
@@ -243,6 +286,15 @@ private module SourceVariableImpl {
private import SourceVariableImpl
private import Ssa::SourceVariables
+pragma[nomagic]
+predicate localScopeSourceVariable(
+ Ssa::SourceVariables::LocalScopeSourceVariable sv, LocalScopeVariable v, Callable c1, Callable c2
+) {
+ sv.getAssignable() = v and
+ sv.getEnclosingCallable() = c1 and
+ v.getCallable() = c2
+}
+
private module CallGraph {
private import semmle.code.csharp.dispatch.Dispatch
@@ -753,34 +805,26 @@ private module Cached {
cached
predicate implicitEntryDefinition(BasicBlock bb, Ssa::SourceVariable v) {
- exists(EntryBasicBlock entry, Callable c |
- c = entry.getEnclosingCallable() and
- // In case `c` has multiple bodies, we want each body to get its own implicit
- // entry definition. In case `c` doesn't have multiple bodies, the line below
- // is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
- // will be in the entry block.
- bb = entry.getFirstNode().getASuccessor().getBasicBlock() and
- c = v.getEnclosingCallable()
- |
- // Captured variable
- exists(LocalScopeVariable lsv |
- v = any(LocalScopeSourceVariable lv | lsv = lv.getAssignable())
- |
- lsv.getCallable() != c
+ exists(Callable c | c = v.getEnclosingCallable() |
+ c = bb.(EntryBasicBlock).getEnclosingCallable() and
+ (
+ // Captured variable
+ exists(LocalScopeVariable lsv |
+ v = any(LocalScopeSourceVariable lv | lsv = lv.getAssignable())
+ |
+ lsv.getCallable() != c
+ )
+ or
+ // Each tracked field and property has an implicit entry definition
+ v instanceof PlainFieldOrPropSourceVariable
)
or
- // Each tracked field and property has an implicit entry definition
- v instanceof PlainFieldOrPropSourceVariable
- or
- v.getAssignable() instanceof Parameter
- )
- }
-
- cached
- AssignableDefinition getADefinition(Ssa::ExplicitDefinition def) {
- exists(Ssa::SourceVariable v, AssignableDefinition ad | explicitDefinition(def, v, ad) |
- result = ad or
- result = getASameOutRefDefAfter(v, ad)
+ // In case `c` has multiple bodies, we want each body to get its own set of
+ // parameter definitions, so we add special writes to the start of the basic
+ // blocks containing the bodies
+ strictcount(c.getBody()) > 1 and
+ v.getAssignable() instanceof Parameter and
+ bb.getANode().isBefore(c.getBody())
)
}
@@ -800,7 +844,7 @@ private module Cached {
predicate variableWriteQualifier(
BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable v, boolean certain
) {
- SsaInput::variableWrite(bb, i, v.getQualifier(), certain) and
+ SsaImplInput::variableWrite(bb, i, v.getQualifier(), certain) and
// Eliminate corner case where a call definition can overlap with a
// qualifier definition: if method `M` updates field `F`, then a call
// to `M` is both an update of `x.M` and `x.M.M`, so the former call
@@ -809,41 +853,15 @@ private module Cached {
not updatesNamedFieldOrProp(bb, i, _, v, _)
}
- cached
- predicate explicitDefinition(WriteDefinition def, Ssa::SourceVariable v, AssignableDefinition ad) {
- exists(BasicBlock bb, int i |
- def.definesAt(v, bb, i) and
- variableDefinition(bb, i, v, ad)
- )
- }
-
- cached
- predicate isLiveAtEndOfBlock(Definition def, BasicBlock bb) {
- Impl::ssaDefReachesEndOfBlock(bb, def, _)
- }
-
- cached
- Definition phiHasInputFromBlock(Ssa::PhiNode phi, BasicBlock bb) {
- Impl::phiHasInputFromBlock(phi, result, bb)
- }
-
- cached
- AssignableRead getAReadAtNode(Definition def, ControlFlowNode cfn) {
- exists(Ssa::SourceVariable v, BasicBlock bb, int i |
- Impl::ssaDefReachesRead(v, def, bb, i) and
- variableReadActual(bb, i, v) and
- cfn = bb.getNode(i) and
- result.getControlFlowNode() = cfn
- )
- }
-
/**
- * Holds if the value defined at SSA definition `def` can reach a read at `cfn`,
+ * Holds if the value defined at SSA definition `def` can reach a read `read`,
* without passing through any other read.
*/
cached
- predicate firstReadSameVar(Definition def, ControlFlowNode cfn) {
- exists(BasicBlock bb, int i | Impl::firstUse(def, bb, i, true) and cfn = bb.getNode(i))
+ predicate firstReadSameVar(Definition def, AssignableRead read) {
+ exists(BasicBlock bb, int i |
+ Impl::firstUse(def, bb, i, true) and read.getControlFlowNode() = bb.getNode(i)
+ )
}
/**
@@ -861,15 +879,14 @@ private module Cached {
)
}
+ /**
+ * Holds if the SSA definition `def` assigns to `out`/`ref` parameter `p`, and the
+ * parameter may remain unchanged throughout the rest of the enclosing callable.
+ */
cached
- Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
- Impl::uncertainWriteDefinitionInput(def, result)
- }
-
- cached
- predicate isLiveOutRefParameterDefinition(Ssa::Definition def, Parameter p) {
+ predicate isLiveOutRefParameterDefinition(SsaDefinition def, Parameter p) {
p.isOutOrRef() and
- exists(Ssa::SourceVariable v, Ssa::Definition def0, BasicBlock bb, int i |
+ exists(Ssa::SourceVariable v, SsaDefinition def0, BasicBlock bb, int i |
v = def.getSourceVariable() and
p = v.getAssignable() and
def = def0.getAnUltimateDefinition() and
@@ -951,6 +968,43 @@ private module Cached {
import Cached
+deprecated AssignableDefinition getADefinition(Ssa::ExplicitDefinition def) {
+ exists(Ssa::SourceVariable v, AssignableDefinition ad | explicitDefinition(def, v, ad) |
+ result = ad or
+ result = getASameOutRefDefAfter(v, ad)
+ )
+}
+
+deprecated predicate explicitDefinition(
+ WriteDefinition def, Ssa::SourceVariable v, AssignableDefinition ad
+) {
+ exists(BasicBlock bb, int i |
+ def.definesAt(v, bb, i) and
+ variableDefinition(bb, i, v, ad)
+ )
+}
+
+deprecated predicate isLiveAtEndOfBlock(Definition def, BasicBlock bb) {
+ Impl::ssaDefReachesEndOfBlock(bb, def, _)
+}
+
+deprecated Definition phiHasInputFromBlock(Ssa::PhiNode phi, BasicBlock bb) {
+ Impl::phiHasInputFromBlock(phi, result, bb)
+}
+
+deprecated AssignableRead getAReadAtNode(Definition def, ControlFlowNode cfn) {
+ exists(Ssa::SourceVariable v, BasicBlock bb, int i |
+ Impl::ssaDefReachesRead(v, def, bb, i) and
+ variableReadActual(bb, i, v) and
+ cfn = bb.getNode(i) and
+ result.getControlFlowNode() = cfn
+ )
+}
+
+deprecated Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
+ Impl::uncertainWriteDefinitionInput(def, result)
+}
+
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
private import codeql.util.Boolean
@@ -958,20 +1012,20 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
}
- Expr getARead(Definition def) { exists(getAReadAtNode(def, result)) }
+ Expr getARead(Definition def) { def.(SsaDefinition).getARead().getControlFlowNode() = result }
- predicate ssaDefHasSource(WriteDefinition def) {
+ predicate ssaDefHasSource(Impl::WriteDefinition def) {
// exclude flow directly from RHS to SSA definition, as we instead want to
// go from RHS to matching assignable definition, and from there to SSA definition
- def instanceof Ssa::ImplicitParameterDefinition
+ def instanceof SsaParameterInit
}
/**
- * Allows for flow into uncertain defintions that are not call definitions,
+ * Allows for flow into uncertain definitions that are not call definitions,
* as we, conservatively, consider such definitions to be certain.
*/
- predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) {
- def instanceof Ssa::ExplicitDefinition
+ predicate allowFlowIntoUncertainDef(Impl::UncertainWriteDefinition def) {
+ def instanceof SsaExplicitWrite
or
def =
any(Ssa::ImplicitQualifierDefinition qdef |
@@ -995,3 +1049,58 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
}
private module DataFlowIntegrationImpl = Impl::DataFlowIntegration;
+
+deprecated private module MultiBodyNearestLocationInput implements NearestLocationInputSig {
+ class C = MultiBodyParameterDefinition;
+
+ predicate relevantLocations(MultiBodyParameterDefinition def, Location l1, Location l2) {
+ exists(Callable c, ControlFlowNode n |
+ l1 = def.getParameter().getALocation() and
+ n = def.getBasicBlock().getANode() and
+ n.isBefore(c.getBody()) and
+ l2 = n.getLocation()
+ )
+ }
+}
+
+pragma[nomagic]
+deprecated private predicate implicitEntryDef(
+ Ssa::ImplicitEntryDefinition def, Ssa::SourceVariable v, Callable c
+) {
+ v = def.getSourceVariable() and
+ c = def.getCallable()
+}
+
+/**
+ * An SSA definition representing the implicit initialization of a parameter
+ * at the beginning of a callable.
+ */
+abstract deprecated class ParameterDefinitionImpl extends Ssa::Definition {
+ /** Gets the parameter that this definition represents. */
+ abstract Parameter getParameter();
+
+ override string toString() {
+ result = "SSA param(" + pragma[only_bind_out](this.getParameter()) + ")"
+ }
+}
+
+deprecated class MultiBodyParameterDefinition extends ParameterDefinitionImpl,
+ Ssa::ImplicitEntryDefinition
+{
+ private Parameter p;
+
+ MultiBodyParameterDefinition() {
+ exists(Ssa::SourceVariable sv, Callable c |
+ implicitEntryDef(this, sv, c) and
+ localScopeSourceVariable(sv, p, _, c)
+ )
+ }
+
+ override Parameter getParameter() { result = p }
+
+ override string toString() { result = ParameterDefinitionImpl.super.toString() }
+
+ override Location getLocation() {
+ NearestLocation::nearestLocation(this, result, _)
+ }
+}
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
index fbc09e7ec52d..34b5ec9a5e85 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
@@ -9,7 +9,7 @@ module Private {
class SsaVariable = SU::SsaVariable;
- class SsaPhiNode = CS::Ssa::PhiNode;
+ class SsaPhiNode = CS::SsaPhiDefinition;
class Expr = CS::ControlFlowNodes::ExprNode;
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
index e53e3a44276d..b85f68883ab6 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
@@ -19,7 +19,7 @@ private module Impl {
}
/** Holds if SSA definition `def` equals `e + delta`. */
- predicate ssaUpdateStep(ExplicitDefinition def, ExprNode e, int delta) {
+ predicate ssaUpdateStep(SsaExplicitWrite def, ExprNode e, int delta) {
exists(ControlFlowNode cfn | cfn = def.getControlFlowNode() |
e = cfn.(ExprNode::Assignment).getRightOperand() and
delta = 0 and
@@ -106,7 +106,7 @@ private module Impl {
* - `isEq = true` : `def == e + delta`
* - `isEq = false` : `def != e + delta`
*/
- Guard eqFlowCond(Definition def, ExprNode e, int delta, boolean isEq, boolean testIsTrue) {
+ Guard eqFlowCond(SsaDefinition def, ExprNode e, int delta, boolean isEq, boolean testIsTrue) {
exists(boolean eqpolarity |
result.isEquality(ssaRead(def, delta), e, eqpolarity) and
testIsTrue = [false, true] and
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
index f6dd4911256c..48ed00858a0d 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
@@ -13,9 +13,9 @@ module Private {
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
- class SsaVariable = CS::Ssa::Definition;
+ class SsaVariable = CS::SsaDefinition;
- class SsaPhiNode = CS::Ssa::PhiNode;
+ class SsaPhiNode = CS::SsaPhiDefinition;
class VarAccess = RU::ExprNode::AssignableAccess;
@@ -35,7 +35,7 @@ module Private {
class Expr = CS::ControlFlowNodes::ExprNode;
- class VariableUpdate = CS::Ssa::ExplicitDefinition;
+ class VariableUpdate = CS::SsaExplicitWrite;
class Field = CS::Field;
@@ -122,46 +122,34 @@ private module Impl {
}
/** Returns the underlying variable update of the explicit SSA variable `v`. */
- Ssa::ExplicitDefinition getExplicitSsaAssignment(Ssa::ExplicitDefinition v) { result = v }
+ SsaExplicitWrite getExplicitSsaAssignment(SsaExplicitWrite v) { result = v }
/** Returns the assignment of the variable update `def`. */
- ExprNode getExprFromSsaAssignment(Ssa::ExplicitDefinition def) {
- exists(AssignableDefinition adef |
- adef = def.getADefinition() and
- hasChild(adef.getExpr(), adef.getSource(), def.getControlFlowNode(), result)
- )
- or
- exists(AssignableDefinitions::AssignOperationDefinition adef |
- adef = def.getADefinition() and
- result.getExpr() = adef.getSource()
- )
- }
+ ExprNode getExprFromSsaAssignment(SsaExplicitWrite def) { result.getExpr() = def.getValue() }
/** Holds if `def` can have any sign. */
- predicate explicitSsaDefWithAnySign(Ssa::ExplicitDefinition def) {
- not exists(def.getADefinition().getSource()) and
- not def.getElement() instanceof MutatorOperation
+ predicate explicitSsaDefWithAnySign(SsaExplicitWrite def) {
+ not exists(def.getValue()) and
+ not def.getDefiningExpr() instanceof MutatorOperation
}
/** Returns the operand of the operation if `def` is a decrement. */
- ExprNode getDecrementOperand(Ssa::ExplicitDefinition def) {
- hasChild(def.getElement(), def.getElement().(DecrementOperation).getOperand(),
- def.getControlFlowNode(), result)
+ ExprNode getDecrementOperand(SsaExplicitWrite def) {
+ result.getExpr() = def.getDefiningExpr().(DecrementOperation).getOperand()
}
/** Returns the operand of the operation if `def` is an increment. */
- ExprNode getIncrementOperand(Ssa::ExplicitDefinition def) {
- hasChild(def.getElement(), def.getElement().(IncrementOperation).getOperand(),
- def.getControlFlowNode(), result)
+ ExprNode getIncrementOperand(SsaExplicitWrite def) {
+ result.getExpr() = def.getDefiningExpr().(IncrementOperation).getOperand()
}
/** Gets the variable underlying the implicit SSA variable `def`. */
- Declaration getImplicitSsaDeclaration(Ssa::ImplicitDefinition def) {
+ Declaration getImplicitSsaDeclaration(SsaImplicitWrite def) {
result = def.getSourceVariable().getAssignable()
}
/** Holds if the variable underlying the implicit SSA variable `def` is not a field. */
- predicate nonFieldImplicitSsaDefinition(Ssa::ImplicitDefinition def) {
+ predicate nonFieldImplicitSsaDefinition(SsaImplicitWrite def) {
not getImplicitSsaDeclaration(def) instanceof Field
}
@@ -245,7 +233,7 @@ private module Impl {
)
}
- ExprNode getARead(Ssa::Definition v) { exists(v.getAReadAtNode(result)) }
+ ExprNode getARead(SsaDefinition v) { v.getARead().getControlFlowNode() = result }
Field getField(ExprNode fa) { result = fa.getExpr().(FieldAccess).getTarget() }
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll
index 6da6ec8b11e6..77833591c3eb 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll
@@ -5,9 +5,9 @@
private import csharp as CS
private import SsaReadPositionCommon
-class SsaVariable = CS::Ssa::Definition;
+class SsaVariable = CS::SsaDefinition;
-class SsaPhiNode = CS::Ssa::PhiNode;
+class SsaPhiNode = CS::SsaPhiDefinition;
class BasicBlock = CS::BasicBlock;
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll
index 55267fad17cf..33afe07dae33 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll
@@ -10,24 +10,24 @@ private import ConstantUtils
private class ExprNode = ControlFlowNodes::ExprNode;
/** An SSA variable. */
-class SsaVariable extends Definition {
+class SsaVariable extends SsaDefinition {
/** Gets a read of this SSA variable. */
- ExprNode getAUse() { exists(this.getAReadAtNode(result)) }
+ ExprNode getAUse() { this.getARead().getControlFlowNode() = result }
}
/** Gets a node that reads `src` via an SSA explicit definition. */
ExprNode getAnExplicitDefinitionRead(ExprNode src) {
- exists(ExplicitDefinition def |
- exists(def.getAReadAtNode(result)) and
- hasChild(def.getElement(), def.getADefinition().getSource(), def.getControlFlowNode(), src)
+ exists(SsaExplicitWrite def |
+ def.getARead().getControlFlowNode() = result and
+ hasChild(def.getDefiningExpr(), def.getValue(), def.getControlFlowNode(), src)
)
}
/**
* Gets an expression that equals `v - delta`.
*/
-ExprNode ssaRead(Definition v, int delta) {
- exists(v.getAReadAtNode(result)) and delta = 0
+ExprNode ssaRead(SsaDefinition v, int delta) {
+ v.getARead().getControlFlowNode() = result and delta = 0
or
exists(ExprNode::AddOperation add, int d1, ConstantIntegerExpr c |
result = add and
@@ -45,15 +45,15 @@ ExprNode ssaRead(Definition v, int delta) {
delta = d1 + c.getIntValue()
)
or
- v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PreIncrExpr) = result and delta = 0
+ v.(SsaExplicitWrite).getControlFlowNode().(ExprNode::PreIncrExpr) = result and delta = 0
or
- v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PreDecrExpr) = result and delta = 0
+ v.(SsaExplicitWrite).getControlFlowNode().(ExprNode::PreDecrExpr) = result and delta = 0
or
- v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PostIncrExpr) = result and delta = 1 // x++ === ++x - 1
+ v.(SsaExplicitWrite).getControlFlowNode().(ExprNode::PostIncrExpr) = result and delta = 1 // x++ === ++x - 1
or
- v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PostDecrExpr) = result and delta = -1 // x-- === --x + 1
+ v.(SsaExplicitWrite).getControlFlowNode().(ExprNode::PostDecrExpr) = result and delta = -1 // x-- === --x + 1
or
- v.(ExplicitDefinition).getControlFlowNode().(ExprNode::Assignment) = result and delta = 0
+ v.(SsaExplicitWrite).getControlFlowNode().(ExprNode::Assignment) = result and delta = 0
or
result.(ExprNode::AssignExpr).getRightOperand() = ssaRead(v, delta)
}
diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll
index 6d535025a195..15a64d12b499 100644
--- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll
@@ -99,7 +99,11 @@ private module Internal {
or
ac instanceof AssignableWrite and isRead = false
} or
- TDispatchOperatorCall(OperatorCall oc) { not oc.isLateBound() } or
+ TDispatchOperatorCall(OperatorCall oc) {
+ not oc.isLateBound() and
+ not oc instanceof CompoundAssignmentOperatorCall
+ } or
+ TDispatchCompoundAssignmentOperatorCall(CompoundAssignmentOperatorCall caoc) or
TDispatchReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) {
isReflectionCall(mc, name, object, qualifier, args)
} or
@@ -886,6 +890,20 @@ private module Internal {
override Operator getAStaticTarget() { result = this.getCall().getTarget() }
}
+ private class DispatchCompoundAssignmentOperatorCall extends DispatchOverridableCall,
+ TDispatchCompoundAssignmentOperatorCall
+ {
+ override CompoundAssignmentOperatorCall getCall() {
+ this = TDispatchCompoundAssignmentOperatorCall(result)
+ }
+
+ override Expr getArgument(int i) { result = this.getCall().getArgument(i) }
+
+ override Expr getQualifier() { result = this.getCall().getQualifier() }
+
+ override Operator getAStaticTarget() { result = this.getCall().getTarget() }
+ }
+
/**
* A call to an accessor.
*
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
index 8c7dd80da243..f65b13bf8ecb 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
@@ -94,13 +94,17 @@ class AssignOperation extends Assignment, @assign_op_expr {
}
/**
- * A compound assignment operation that implicitly invokes an operator.
- * For example, `x += y` assigns the result of `x + y` to `x`.
+ * A compound assignment operation that invokes an operator.
+ *
+ * (1) `x += y` invokes the compound assignment operator `+=` (if it exists).
+ * (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`.
*
* Either an arithmetic assignment operation (`AssignArithmeticOperation`) or a bitwise
* assignment operation (`AssignBitwiseOperation`).
*/
-class AssignCallOperation extends AssignOperation, OperatorCall, @assign_op_call_expr {
+class AssignCallOperation extends AssignOperation, OperatorCall, QualifiableExpr,
+ @assign_op_call_expr
+{
override string toString() { result = AssignOperation.super.toString() }
}
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
index 63bd0c18a75c..9dbf898e2864 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
@@ -529,6 +529,19 @@ class ExtensionOperatorCall extends OperatorCall {
ExtensionOperatorCall() { this.getTarget() instanceof ExtensionOperator }
override string getAPrimaryQlClass() { result = "ExtensionOperatorCall" }
+
+ private predicate isOrdinaryStaticCall() {
+ not exists(Expr e | e = this.getChildExpr(-1) | not e instanceof TypeAccess)
+ }
+
+ override Expr getArgument(int i) {
+ exists(int j | result = this.getChildExpr(j) |
+ i >= 0 and
+ if this.isOrdinaryStaticCall() or this.getTarget() instanceof CompoundAssignmentOperator
+ then j = i
+ else j = i - 1
+ )
+ }
}
/**
@@ -557,6 +570,58 @@ class MutatorOperatorCall extends OperatorCall {
predicate isPostfix() { mutator_invocation_mode(this, 2) }
}
+/**
+ * A call to a compound assignment operator, for example `this += other`
+ * on line 7 in
+ *
+ * ```csharp
+ * class A {
+ * public void operator +=(A other) {
+ * ...
+ * }
+ *
+ * public void Add(A other) {
+ * this += other;
+ * }
+ * }
+ * ```
+ */
+class CompoundAssignmentOperatorCall extends AssignCallOperation {
+ CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator }
+
+ override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 }
+
+ /** Gets the qualifier of this compound assignment operator call. */
+ override Expr getQualifier() { result = this.getChildExpr(0) }
+}
+
+/**
+ * A call to a compound assignment extension operator, for example `s1 *= s2` on
+ * line 9 in
+ *
+ * ```csharp
+ * static class MyExtensions {
+ * extension(string s) {
+ * public void operator *=(string other) { ... }
+ * }
+ * }
+ *
+ * class A {
+ * void M(string s1, string s2) {
+ * s1 *= s2;
+ * }
+ * }
+ */
+class ExtensionCompoundAssignmentOperatorCall extends CompoundAssignmentOperatorCall,
+ ExtensionOperatorCall
+{
+ override Expr getArgument(int i) { result = ExtensionOperatorCall.super.getArgument(i) }
+
+ override Expr getQualifier() { none() }
+
+ override string getAPrimaryQlClass() { result = "ExtensionCompoundAssignmentOperatorCall" }
+}
+
private class DelegateLikeCall_ = @delegate_invocation_expr or @function_pointer_invocation_expr;
/**
diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme
index 19b8cc3e2dc7..3cabc77473cb 100644
--- a/csharp/ql/lib/semmlecode.csharp.dbscheme
+++ b/csharp/ql/lib/semmlecode.csharp.dbscheme
@@ -1338,7 +1338,8 @@ dynamic_member_name(
@qualifiable_expr = @member_access_expr
| @method_invocation_expr
- | @element_access_expr;
+ | @element_access_expr
+ | @assign_op_call_expr;
conditional_access(
unique int id: @qualifiable_expr ref);
@@ -1362,7 +1363,7 @@ compiler_generated(unique int id: @element ref);
/** CONTROL/DATA FLOW **/
-@control_flow_element = @stmt | @expr;
+@control_flow_element = @stmt | @expr | @parameter;
/* XML Files */
diff --git a/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/old.dbscheme b/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/old.dbscheme
new file mode 100644
index 000000000000..19b8cc3e2dc7
--- /dev/null
+++ b/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/old.dbscheme
@@ -0,0 +1,1504 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/semmlecode.csharp.dbscheme b/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/semmlecode.csharp.dbscheme
new file mode 100644
index 000000000000..ea7ad33252e5
--- /dev/null
+++ b/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/semmlecode.csharp.dbscheme
@@ -0,0 +1,1505 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr
+ | @assign_op_call_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/upgrade.properties b/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/upgrade.properties
new file mode 100644
index 000000000000..1a6c09d74158
--- /dev/null
+++ b/csharp/ql/lib/upgrades/19b8cc3e2dc768d4cbc03d6e3773b709bbebd036/upgrade.properties
@@ -0,0 +1,2 @@
+description: Add @assign_op_call_expr to @qualifiable_expr.
+compatibility: full
diff --git a/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/old.dbscheme b/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/old.dbscheme
new file mode 100644
index 000000000000..ea7ad33252e5
--- /dev/null
+++ b/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/old.dbscheme
@@ -0,0 +1,1505 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr
+ | @assign_op_call_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/semmlecode.csharp.dbscheme b/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/semmlecode.csharp.dbscheme
new file mode 100644
index 000000000000..3cabc77473cb
--- /dev/null
+++ b/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/semmlecode.csharp.dbscheme
@@ -0,0 +1,1505 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+compilation_info(
+ int id : @compilation ref,
+ string info_key: string ref,
+ string info_value: string ref
+)
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile.rsp` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * Overlay support
+ */
+
+/**
+ * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`,
+ * along with an `overlayChangedFiles` tuple for each new/modified/deleted file,
+ * when building an overlay database, and these can be used by the discard predicates.
+ */
+databaseMetadata(
+ string metadataKey : string ref,
+ string value : string ref
+);
+
+overlayChangedFiles(
+ string path : string ref
+);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive
+ | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints
+ | @declaration_with_accessors | @callable_accessor | @operator | @method
+ | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr
+ | @xmllocatable | @commentline | @commentblock | @asp_element
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+| 34 = @inline_array_type
+| 35 = @extension_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type | @extension_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extension_receiver_type(
+ unique int extension: @extension_type ref,
+ int receiver_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event | @operator;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+@has_scoped_annotation = @local_scope_variable
+
+scoped_annotation(
+ int id: @has_scoped_annotation ref,
+ int kind: int ref // scoped ref = 1, scoped value = 2
+ );
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @utf16_string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+| 135 = @utf8_string_literal_expr
+/* C# 12.0 */
+| 136 = @collection_expr
+| 137 = @spread_element_expr
+| 138 = @interpolated_string_insert_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@add_operation = @add_expr | @assign_add_expr;
+@sub_operation = @sub_expr | @assign_sub_expr;
+@mul_operation = @mul_expr | @assign_mul_expr;
+@div_operation = @div_expr | @assign_div_expr;
+@rem_operation = @rem_expr | @assign_rem_expr;
+@and_operation = @bit_and_expr | @assign_and_expr;
+@xor_operation = @bit_xor_expr | @assign_xor_expr;
+@or_operation = @bit_or_expr | @assign_or_expr;
+@lshift_operation = @lshift_expr | @assign_lshift_expr;
+@rshift_operation = @rshift_expr | @assign_rshift_expr;
+@urshift_operation = @urshift_expr | @assign_urshift_expr;
+@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr
+ | @assign_op_call_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/* Compiler generated */
+
+compiler_generated(unique int id: @element ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr | @parameter;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
diff --git a/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/upgrade.properties b/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/upgrade.properties
new file mode 100644
index 000000000000..cd2dfa3d4d5d
--- /dev/null
+++ b/csharp/ql/lib/upgrades/ea7ad33252e550241975676f09fcc7b0a703deab/upgrade.properties
@@ -0,0 +1,2 @@
+description: Add `@parameter` to `@control_flow_element`
+compatibility: full
diff --git a/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql b/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql
index 8e36f4f1ad1b..295bdba1f7af 100644
--- a/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql
+++ b/csharp/ql/src/Bad Practices/Control-Flow/ConstantCondition.ql
@@ -20,7 +20,7 @@ import semmle.code.csharp.controlflow.Guards as Guards
import codeql.controlflow.queries.ConstantCondition as ConstCond
module ConstCondInput implements ConstCond::InputSig {
- class SsaDefinition = Ssa::Definition;
+ class SsaDefinition = Ssa::SsaDefinition;
class GuardValue = Guards::GuardValue;
diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md
index cdab71341852..32243acfb97f 100644
--- a/csharp/ql/src/CHANGELOG.md
+++ b/csharp/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.2
+
+No user-facing changes.
+
## 1.7.1
### Minor Analysis Improvements
diff --git a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
index 12baac99c78d..cf57707608b4 100644
--- a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
+++ b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
@@ -92,7 +92,7 @@ class RelevantDefinition extends AssignableDefinition {
private predicate isMaybeLive() {
exists(LocalVariable v | v = this.getTarget() |
// SSA definitions are only created for live variables
- this = any(Ssa::ExplicitDefinition ssaDef).getADefinition()
+ this = any(SsaExplicitWrite ssaDef).getDefinition()
or
mayEscape(v)
or
diff --git a/csharp/ql/src/Likely Bugs/Dynamic/BadDynamicCall.ql b/csharp/ql/src/Likely Bugs/Dynamic/BadDynamicCall.ql
index 75f152b38de1..afb44727e34f 100644
--- a/csharp/ql/src/Likely Bugs/Dynamic/BadDynamicCall.ql
+++ b/csharp/ql/src/Likely Bugs/Dynamic/BadDynamicCall.ql
@@ -36,17 +36,16 @@ abstract class BadDynamicCall extends DynamicExpr {
}
private Type possibleTypeForRelevantSource(Variable v, int i, Expr source) {
- exists(AssignableRead read, Ssa::Definition ssaDef, Ssa::ExplicitDefinition ultimateSsaDef |
+ exists(AssignableRead read, SsaDefinition ssaDef, SsaExplicitWrite ultimateSsaDef |
read = this.getARelevantVariableAccess(i) and
v = read.getTarget() and
result = source.getType() and
read = ssaDef.getARead() and
ultimateSsaDef = ssaDef.getAnUltimateDefinition()
|
- ultimateSsaDef.getADefinition() =
- any(AssignableDefinition def | source = def.getSource().stripImplicit())
+ ultimateSsaDef.getValue().stripImplicit() = source
or
- ultimateSsaDef.getADefinition() =
+ ultimateSsaDef.getDefinition() =
any(AssignableDefinitions::ImplicitParameterDefinition p |
source = p.getParameter().getAnAssignedValue().stripImplicit()
)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.qhelp b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.qhelp
index 3c68b74a1d92..4cc76003fbf8 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.qhelp
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.qhelp
@@ -7,6 +7,17 @@
Deserializing an object from untrusted input may result in security problems, such
as denial of service or remote code execution.
+
+Note that a deserialization method is only dangerous if it can instantiate
+arbitrary classes. Serialization frameworks that use a schema to instantiate
+only expected, predefined types are generally not tracked by this query. Such
+frameworks are generally safe with respect to arbitrary-class-instantiation and
+gadget-chain attacks when the schema is trusted and does not permit
+user-controlled type resolution. However, care must be taken to ensure the schema
+strictly limits the allowed types. Permitting common standard library classes
+can still leave the application vulnerable to gadget-chain attacks.
+
Deserializing an object from untrusted input may result in security problems, such
as denial of service or remote code execution.
+
+Note that a deserialization method is only dangerous if it can instantiate
+arbitrary classes. Serialization frameworks that use a schema to instantiate
+only expected, predefined types are generally not tracked by this query. Such
+frameworks are generally safe with respect to arbitrary-class-instantiation and
+gadget-chain attacks when the schema is trusted and does not permit
+user-controlled type resolution. However, care must be taken to ensure the schema
+strictly limits the allowed types. Permitting common standard library classes
+can still leave the application vulnerable to gadget-chain attacks.
+
+
diff --git a/csharp/ql/src/change-notes/released/1.7.2.md b/csharp/ql/src/change-notes/released/1.7.2.md
new file mode 100644
index 000000000000..b950385c16d7
--- /dev/null
+++ b/csharp/ql/src/change-notes/released/1.7.2.md
@@ -0,0 +1,3 @@
+## 1.7.2
+
+No user-facing changes.
diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml
index 7bdec0d85c73..39bbba86c198 100644
--- a/csharp/ql/src/codeql-pack.release.yml
+++ b/csharp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.1
+lastReleaseVersion: 1.7.2
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 25b04cf2dc66..de201743065f 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 1.7.2-dev
+version: 1.7.3-dev
groups:
- csharp
- queries
diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected
index 19aa44a84477..819674d2746d 100644
--- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected
+++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected
@@ -1,73 +1,73 @@
| AccessorCalls.cs:1:7:1:19 | Entry | AccessorCalls.cs:1:7:1:19 | Exit | 11 |
-| AccessorCalls.cs:5:23:5:25 | Entry | AccessorCalls.cs:5:23:5:25 | Exit | 4 |
-| AccessorCalls.cs:5:33:5:35 | Entry | AccessorCalls.cs:5:33:5:35 | Exit | 4 |
-| AccessorCalls.cs:7:32:7:34 | Entry | AccessorCalls.cs:7:32:7:34 | Exit | 4 |
-| AccessorCalls.cs:7:40:7:45 | Entry | AccessorCalls.cs:7:40:7:45 | Exit | 4 |
-| AccessorCalls.cs:10:10:10:11 | Entry | AccessorCalls.cs:10:10:10:11 | Exit | 66 |
-| AccessorCalls.cs:19:10:19:11 | Entry | AccessorCalls.cs:19:10:19:11 | Exit | 90 |
+| AccessorCalls.cs:5:23:5:25 | Entry | AccessorCalls.cs:5:23:5:25 | Exit | 5 |
+| AccessorCalls.cs:5:33:5:35 | Entry | AccessorCalls.cs:5:33:5:35 | Exit | 6 |
+| AccessorCalls.cs:7:32:7:34 | Entry | AccessorCalls.cs:7:32:7:34 | Exit | 5 |
+| AccessorCalls.cs:7:40:7:45 | Entry | AccessorCalls.cs:7:40:7:45 | Exit | 5 |
+| AccessorCalls.cs:10:10:10:11 | Entry | AccessorCalls.cs:10:10:10:11 | Exit | 67 |
+| AccessorCalls.cs:19:10:19:11 | Entry | AccessorCalls.cs:19:10:19:11 | Exit | 91 |
| AccessorCalls.cs:28:10:28:11 | Entry | AccessorCalls.cs:28:10:28:11 | Exit | 33 |
| AccessorCalls.cs:35:10:35:11 | Entry | AccessorCalls.cs:35:10:35:11 | Exit | 42 |
| AccessorCalls.cs:42:10:42:11 | Entry | AccessorCalls.cs:42:10:42:11 | Exit | 46 |
| AccessorCalls.cs:49:10:49:11 | Entry | AccessorCalls.cs:49:10:49:11 | Exit | 64 |
-| AccessorCalls.cs:56:10:56:11 | Entry | AccessorCalls.cs:56:10:56:11 | Exit | 50 |
-| AccessorCalls.cs:61:10:61:11 | Entry | AccessorCalls.cs:61:10:61:11 | Exit | 68 |
-| AccessorCalls.cs:66:10:66:11 | Entry | AccessorCalls.cs:66:10:66:11 | Exit | 104 |
+| AccessorCalls.cs:56:10:56:11 | Entry | AccessorCalls.cs:56:10:56:11 | Exit | 51 |
+| AccessorCalls.cs:61:10:61:11 | Entry | AccessorCalls.cs:61:10:61:11 | Exit | 69 |
+| AccessorCalls.cs:66:10:66:11 | Entry | AccessorCalls.cs:66:10:66:11 | Exit | 107 |
| ArrayCreation.cs:1:7:1:19 | Entry | ArrayCreation.cs:1:7:1:19 | Exit | 11 |
| ArrayCreation.cs:3:11:3:12 | Entry | ArrayCreation.cs:3:11:3:12 | Exit | 7 |
| ArrayCreation.cs:5:12:5:13 | Entry | ArrayCreation.cs:5:12:5:13 | Exit | 8 |
| ArrayCreation.cs:7:11:7:12 | Entry | ArrayCreation.cs:7:11:7:12 | Exit | 12 |
| ArrayCreation.cs:9:12:9:13 | Entry | ArrayCreation.cs:9:12:9:13 | Exit | 21 |
| Assert.cs:5:7:5:17 | Entry | Assert.cs:5:7:5:17 | Exit | 11 |
-| Assert.cs:7:10:7:11 | Entry | Assert.cs:9:20:9:20 | access to parameter b | 7 |
+| Assert.cs:7:10:7:11 | Entry | Assert.cs:9:20:9:20 | access to parameter b | 8 |
| Assert.cs:7:10:7:11 | Exceptional Exit | Assert.cs:7:10:7:11 | Exceptional Exit | 1 |
| Assert.cs:7:10:7:11 | Exit | Assert.cs:7:10:7:11 | Exit | 1 |
| Assert.cs:9:20:9:20 | After access to parameter b [false] | Assert.cs:9:31:9:32 | "" | 2 |
| Assert.cs:9:20:9:20 | After access to parameter b [true] | Assert.cs:9:24:9:27 | null | 2 |
| Assert.cs:9:20:9:32 | After ... ? ... : ... | Assert.cs:10:9:10:31 | call to method Assert | 12 |
| Assert.cs:10:9:10:31 | After call to method Assert | Assert.cs:7:10:7:11 | Normal Exit | 13 |
-| Assert.cs:14:10:14:11 | Entry | Assert.cs:16:20:16:20 | access to parameter b | 7 |
+| Assert.cs:14:10:14:11 | Entry | Assert.cs:16:20:16:20 | access to parameter b | 8 |
| Assert.cs:14:10:14:11 | Exceptional Exit | Assert.cs:14:10:14:11 | Exceptional Exit | 1 |
| Assert.cs:14:10:14:11 | Exit | Assert.cs:14:10:14:11 | Exit | 1 |
| Assert.cs:16:20:16:20 | After access to parameter b [false] | Assert.cs:16:31:16:32 | "" | 2 |
| Assert.cs:16:20:16:20 | After access to parameter b [true] | Assert.cs:16:24:16:27 | null | 2 |
| Assert.cs:16:20:16:32 | After ... ? ... : ... | Assert.cs:17:9:17:24 | call to method IsNull | 8 |
| Assert.cs:17:9:17:24 | After call to method IsNull | Assert.cs:14:10:14:11 | Normal Exit | 13 |
-| Assert.cs:21:10:21:11 | Entry | Assert.cs:23:20:23:20 | access to parameter b | 7 |
+| Assert.cs:21:10:21:11 | Entry | Assert.cs:23:20:23:20 | access to parameter b | 8 |
| Assert.cs:21:10:21:11 | Exceptional Exit | Assert.cs:21:10:21:11 | Exceptional Exit | 1 |
| Assert.cs:21:10:21:11 | Exit | Assert.cs:21:10:21:11 | Exit | 1 |
| Assert.cs:23:20:23:20 | After access to parameter b [false] | Assert.cs:23:31:23:32 | "" | 2 |
| Assert.cs:23:20:23:20 | After access to parameter b [true] | Assert.cs:23:24:23:27 | null | 2 |
| Assert.cs:23:20:23:32 | After ... ? ... : ... | Assert.cs:24:9:24:27 | call to method IsNotNull | 8 |
| Assert.cs:24:9:24:27 | After call to method IsNotNull | Assert.cs:21:10:21:11 | Normal Exit | 13 |
-| Assert.cs:28:10:28:11 | Entry | Assert.cs:30:20:30:20 | access to parameter b | 7 |
+| Assert.cs:28:10:28:11 | Entry | Assert.cs:30:20:30:20 | access to parameter b | 8 |
| Assert.cs:28:10:28:11 | Exceptional Exit | Assert.cs:28:10:28:11 | Exceptional Exit | 1 |
| Assert.cs:28:10:28:11 | Exit | Assert.cs:28:10:28:11 | Exit | 1 |
| Assert.cs:30:20:30:20 | After access to parameter b [false] | Assert.cs:30:31:30:32 | "" | 2 |
| Assert.cs:30:20:30:20 | After access to parameter b [true] | Assert.cs:30:24:30:27 | null | 2 |
| Assert.cs:30:20:30:32 | After ... ? ... : ... | Assert.cs:31:9:31:32 | call to method IsTrue | 12 |
| Assert.cs:31:9:31:32 | After call to method IsTrue | Assert.cs:28:10:28:11 | Normal Exit | 13 |
-| Assert.cs:35:10:35:11 | Entry | Assert.cs:37:20:37:20 | access to parameter b | 7 |
+| Assert.cs:35:10:35:11 | Entry | Assert.cs:37:20:37:20 | access to parameter b | 8 |
| Assert.cs:35:10:35:11 | Exceptional Exit | Assert.cs:35:10:35:11 | Exceptional Exit | 1 |
| Assert.cs:35:10:35:11 | Exit | Assert.cs:35:10:35:11 | Exit | 1 |
| Assert.cs:37:20:37:20 | After access to parameter b [false] | Assert.cs:37:31:37:32 | "" | 2 |
| Assert.cs:37:20:37:20 | After access to parameter b [true] | Assert.cs:37:24:37:27 | null | 2 |
| Assert.cs:37:20:37:32 | After ... ? ... : ... | Assert.cs:38:9:38:32 | call to method IsTrue | 12 |
| Assert.cs:38:9:38:32 | After call to method IsTrue | Assert.cs:35:10:35:11 | Normal Exit | 13 |
-| Assert.cs:42:10:42:11 | Entry | Assert.cs:44:20:44:20 | access to parameter b | 7 |
+| Assert.cs:42:10:42:11 | Entry | Assert.cs:44:20:44:20 | access to parameter b | 8 |
| Assert.cs:42:10:42:11 | Exceptional Exit | Assert.cs:42:10:42:11 | Exceptional Exit | 1 |
| Assert.cs:42:10:42:11 | Exit | Assert.cs:42:10:42:11 | Exit | 1 |
| Assert.cs:44:20:44:20 | After access to parameter b [false] | Assert.cs:44:31:44:32 | "" | 2 |
| Assert.cs:44:20:44:20 | After access to parameter b [true] | Assert.cs:44:24:44:27 | null | 2 |
| Assert.cs:44:20:44:32 | After ... ? ... : ... | Assert.cs:45:9:45:33 | call to method IsFalse | 12 |
| Assert.cs:45:9:45:33 | After call to method IsFalse | Assert.cs:42:10:42:11 | Normal Exit | 13 |
-| Assert.cs:49:10:49:11 | Entry | Assert.cs:51:20:51:20 | access to parameter b | 7 |
+| Assert.cs:49:10:49:11 | Entry | Assert.cs:51:20:51:20 | access to parameter b | 8 |
| Assert.cs:49:10:49:11 | Exceptional Exit | Assert.cs:49:10:49:11 | Exceptional Exit | 1 |
| Assert.cs:49:10:49:11 | Exit | Assert.cs:49:10:49:11 | Exit | 1 |
| Assert.cs:51:20:51:20 | After access to parameter b [false] | Assert.cs:51:31:51:32 | "" | 2 |
| Assert.cs:51:20:51:20 | After access to parameter b [true] | Assert.cs:51:24:51:27 | null | 2 |
| Assert.cs:51:20:51:32 | After ... ? ... : ... | Assert.cs:52:9:52:33 | call to method IsFalse | 12 |
| Assert.cs:52:9:52:33 | After call to method IsFalse | Assert.cs:49:10:49:11 | Normal Exit | 13 |
-| Assert.cs:56:10:56:11 | Entry | Assert.cs:58:20:58:20 | access to parameter b | 7 |
+| Assert.cs:56:10:56:11 | Entry | Assert.cs:58:20:58:20 | access to parameter b | 8 |
| Assert.cs:56:10:56:11 | Exceptional Exit | Assert.cs:56:10:56:11 | Exceptional Exit | 1 |
| Assert.cs:56:10:56:11 | Exit | Assert.cs:56:10:56:11 | Exit | 1 |
| Assert.cs:58:20:58:20 | After access to parameter b [false] | Assert.cs:58:31:58:32 | "" | 2 |
@@ -77,7 +77,7 @@
| Assert.cs:59:23:59:31 | After ... != ... [false] | Assert.cs:59:23:59:31 | After ... != ... [false] | 1 |
| Assert.cs:59:23:59:31 | After ... != ... [true] | Assert.cs:59:36:59:36 | access to parameter b | 2 |
| Assert.cs:59:23:59:36 | After ... && ... | Assert.cs:59:9:59:37 | call to method IsTrue | 2 |
-| Assert.cs:63:10:63:11 | Entry | Assert.cs:65:20:65:20 | access to parameter b | 7 |
+| Assert.cs:63:10:63:11 | Entry | Assert.cs:65:20:65:20 | access to parameter b | 8 |
| Assert.cs:63:10:63:11 | Exceptional Exit | Assert.cs:63:10:63:11 | Exceptional Exit | 1 |
| Assert.cs:63:10:63:11 | Exit | Assert.cs:63:10:63:11 | Exit | 1 |
| Assert.cs:65:20:65:20 | After access to parameter b [false] | Assert.cs:65:31:65:32 | "" | 2 |
@@ -87,7 +87,7 @@
| Assert.cs:66:24:66:32 | After ... == ... [false] | Assert.cs:66:37:66:37 | access to parameter b | 2 |
| Assert.cs:66:24:66:32 | After ... == ... [true] | Assert.cs:66:24:66:32 | After ... == ... [true] | 1 |
| Assert.cs:66:24:66:37 | After ... \|\| ... | Assert.cs:66:9:66:38 | call to method IsFalse | 2 |
-| Assert.cs:70:10:70:12 | Entry | Assert.cs:72:20:72:20 | access to parameter b | 7 |
+| Assert.cs:70:10:70:12 | Entry | Assert.cs:72:20:72:20 | access to parameter b | 8 |
| Assert.cs:70:10:70:12 | Exceptional Exit | Assert.cs:70:10:70:12 | Exceptional Exit | 1 |
| Assert.cs:70:10:70:12 | Exit | Assert.cs:70:10:70:12 | Exit | 1 |
| Assert.cs:72:20:72:20 | After access to parameter b [false] | Assert.cs:72:31:72:32 | "" | 2 |
@@ -97,7 +97,7 @@
| Assert.cs:73:23:73:31 | After ... == ... [false] | Assert.cs:73:23:73:31 | After ... == ... [false] | 1 |
| Assert.cs:73:23:73:31 | After ... == ... [true] | Assert.cs:73:36:73:36 | access to parameter b | 2 |
| Assert.cs:73:23:73:36 | After ... && ... | Assert.cs:73:9:73:37 | call to method IsTrue | 2 |
-| Assert.cs:77:10:77:12 | Entry | Assert.cs:79:20:79:20 | access to parameter b | 7 |
+| Assert.cs:77:10:77:12 | Entry | Assert.cs:79:20:79:20 | access to parameter b | 8 |
| Assert.cs:77:10:77:12 | Exceptional Exit | Assert.cs:77:10:77:12 | Exceptional Exit | 1 |
| Assert.cs:77:10:77:12 | Exit | Assert.cs:77:10:77:12 | Exit | 1 |
| Assert.cs:79:20:79:20 | After access to parameter b [false] | Assert.cs:79:31:79:32 | "" | 2 |
@@ -107,7 +107,7 @@
| Assert.cs:80:24:80:32 | After ... != ... [false] | Assert.cs:80:37:80:37 | access to parameter b | 2 |
| Assert.cs:80:24:80:32 | After ... != ... [true] | Assert.cs:80:24:80:32 | After ... != ... [true] | 1 |
| Assert.cs:80:24:80:37 | After ... \|\| ... | Assert.cs:80:9:80:38 | call to method IsFalse | 2 |
-| Assert.cs:84:10:84:12 | Entry | Assert.cs:86:20:86:20 | access to parameter b | 7 |
+| Assert.cs:84:10:84:12 | Entry | Assert.cs:86:20:86:20 | access to parameter b | 8 |
| Assert.cs:84:10:84:12 | Exceptional Exit | Assert.cs:84:10:84:12 | Exceptional Exit | 1 |
| Assert.cs:84:10:84:12 | Exit | Assert.cs:84:10:84:12 | Exit | 1 |
| Assert.cs:86:20:86:20 | After access to parameter b [false] | Assert.cs:86:31:86:32 | "" | 2 |
@@ -166,20 +166,20 @@
| Assert.cs:127:24:127:32 | After ... != ... [false] | Assert.cs:127:37:127:38 | After !... | 4 |
| Assert.cs:127:24:127:32 | After ... != ... [true] | Assert.cs:127:24:127:32 | After ... != ... [true] | 1 |
| Assert.cs:127:24:127:38 | After ... \|\| ... | Assert.cs:127:9:127:39 | call to method IsFalse | 2 |
-| Assert.cs:131:18:131:32 | Entry | Assert.cs:131:18:131:32 | Exit | 4 |
-| Assert.cs:138:10:138:12 | Entry | Assert.cs:140:9:140:35 | call to method AssertTrueFalse | 9 |
+| Assert.cs:131:18:131:32 | Entry | Assert.cs:131:18:131:32 | Exit | 7 |
+| Assert.cs:138:10:138:12 | Entry | Assert.cs:140:9:140:35 | call to method AssertTrueFalse | 12 |
| Assert.cs:138:10:138:12 | Exceptional Exit | Assert.cs:138:10:138:12 | Exceptional Exit | 1 |
| Assert.cs:138:10:138:12 | Exit | Assert.cs:138:10:138:12 | Exit | 1 |
| Assert.cs:140:9:140:35 | After call to method AssertTrueFalse | Assert.cs:138:10:138:12 | Normal Exit | 5 |
| Assignments.cs:1:7:1:17 | Entry | Assignments.cs:1:7:1:17 | Exit | 11 |
| Assignments.cs:3:10:3:10 | Entry | Assignments.cs:3:10:3:10 | Exit | 62 |
-| Assignments.cs:14:18:14:35 | Entry | Assignments.cs:14:18:14:35 | Exit | 4 |
-| Assignments.cs:17:40:17:40 | Entry | Assignments.cs:17:40:17:40 | Exit | 7 |
-| Assignments.cs:27:10:27:23 | Entry | Assignments.cs:27:10:27:23 | Exit | 12 |
-| Assignments.cs:32:10:32:22 | Entry | Assignments.cs:32:10:32:22 | Exit | 19 |
+| Assignments.cs:14:18:14:35 | Entry | Assignments.cs:14:18:14:35 | Exit | 6 |
+| Assignments.cs:17:40:17:40 | Entry | Assignments.cs:17:40:17:40 | Exit | 9 |
+| Assignments.cs:27:10:27:23 | Entry | Assignments.cs:27:10:27:23 | Exit | 13 |
+| Assignments.cs:32:10:32:22 | Entry | Assignments.cs:32:10:32:22 | Exit | 22 |
| Assignments.cs:38:10:38:11 | Entry | Assignments.cs:38:10:38:11 | Exit | 52 |
| BreakInTry.cs:1:7:1:16 | Entry | BreakInTry.cs:1:7:1:16 | Exit | 11 |
-| BreakInTry.cs:3:10:3:11 | Entry | BreakInTry.cs:7:33:7:36 | access to parameter args | 6 |
+| BreakInTry.cs:3:10:3:11 | Entry | BreakInTry.cs:7:33:7:36 | access to parameter args | 7 |
| BreakInTry.cs:7:13:11:13 | After foreach (... ... in ...) ... | BreakInTry.cs:15:17:15:28 | ... == ... | 8 |
| BreakInTry.cs:7:26:7:28 | String arg | BreakInTry.cs:9:21:9:31 | ... == ... | 7 |
| BreakInTry.cs:7:33:7:36 | After access to parameter args [empty] | BreakInTry.cs:7:33:7:36 | After access to parameter args [empty] | 1 |
@@ -189,7 +189,7 @@
| BreakInTry.cs:15:13:16:17 | After if (...) ... | BreakInTry.cs:3:10:3:11 | Exit | 6 |
| BreakInTry.cs:15:17:15:28 | After ... == ... [false] | BreakInTry.cs:15:17:15:28 | After ... == ... [false] | 1 |
| BreakInTry.cs:15:17:15:28 | After ... == ... [true] | BreakInTry.cs:16:17:16:17 | ; | 2 |
-| BreakInTry.cs:20:10:20:11 | Entry | BreakInTry.cs:22:29:22:32 | access to parameter args | 4 |
+| BreakInTry.cs:20:10:20:11 | Entry | BreakInTry.cs:22:29:22:32 | access to parameter args | 5 |
| BreakInTry.cs:22:9:34:9 | After foreach (... ... in ...) ... | BreakInTry.cs:20:10:20:11 | Exit | 5 |
| BreakInTry.cs:22:22:22:24 | String arg | BreakInTry.cs:26:21:26:31 | ... == ... | 9 |
| BreakInTry.cs:22:29:22:32 | After access to parameter args [empty] | BreakInTry.cs:22:29:22:32 | After access to parameter args [empty] | 1 |
@@ -201,7 +201,7 @@
| BreakInTry.cs:31:17:32:21 | After if (...) ... | BreakInTry.cs:30:13:33:13 | After {...} | 2 |
| BreakInTry.cs:31:21:31:32 | After ... == ... [false] | BreakInTry.cs:31:21:31:32 | After ... == ... [false] | 1 |
| BreakInTry.cs:31:21:31:32 | After ... == ... [true] | BreakInTry.cs:32:21:32:21 | ; | 2 |
-| BreakInTry.cs:38:10:38:11 | Entry | BreakInTry.cs:42:17:42:28 | ... == ... | 9 |
+| BreakInTry.cs:38:10:38:11 | Entry | BreakInTry.cs:42:17:42:28 | ... == ... | 10 |
| BreakInTry.cs:38:10:38:11 | Normal Exit | BreakInTry.cs:38:10:38:11 | Exit | 2 |
| BreakInTry.cs:40:9:52:9 | After try {...} ... | BreakInTry.cs:39:5:54:5 | After {...} | 3 |
| BreakInTry.cs:42:17:42:28 | After ... == ... [false] | BreakInTry.cs:41:9:44:9 | After {...} | 3 |
@@ -213,7 +213,7 @@
| BreakInTry.cs:47:33:47:36 | After access to parameter args [non-empty] | BreakInTry.cs:47:33:47:36 | After access to parameter args [non-empty] | 1 |
| BreakInTry.cs:49:21:49:31 | After ... == ... [false] | BreakInTry.cs:47:13:51:13 | [LoopHeader] foreach (... ... in ...) ... | 4 |
| BreakInTry.cs:49:21:49:31 | After ... == ... [true] | BreakInTry.cs:50:21:50:26 | break; | 3 |
-| BreakInTry.cs:56:10:56:11 | Entry | BreakInTry.cs:60:17:60:28 | ... == ... | 9 |
+| BreakInTry.cs:56:10:56:11 | Entry | BreakInTry.cs:60:17:60:28 | ... == ... | 10 |
| BreakInTry.cs:56:10:56:11 | Normal Exit | BreakInTry.cs:56:10:56:11 | Exit | 2 |
| BreakInTry.cs:58:9:70:9 | After try {...} ... | BreakInTry.cs:57:5:71:5 | After {...} | 2 |
| BreakInTry.cs:60:17:60:28 | After ... == ... [false] | BreakInTry.cs:59:9:62:9 | After {...} | 3 |
@@ -229,7 +229,7 @@
| CompileTimeOperators.cs:5:9:5:15 | Entry | CompileTimeOperators.cs:5:9:5:15 | Exit | 7 |
| CompileTimeOperators.cs:10:9:10:14 | Entry | CompileTimeOperators.cs:10:9:10:14 | Exit | 7 |
| CompileTimeOperators.cs:15:10:15:15 | Entry | CompileTimeOperators.cs:15:10:15:15 | Exit | 7 |
-| CompileTimeOperators.cs:20:12:20:17 | Entry | CompileTimeOperators.cs:20:12:20:17 | Exit | 7 |
+| CompileTimeOperators.cs:20:12:20:17 | Entry | CompileTimeOperators.cs:20:12:20:17 | Exit | 8 |
| CompileTimeOperators.cs:26:7:26:22 | Entry | CompileTimeOperators.cs:26:7:26:22 | Exit | 11 |
| CompileTimeOperators.cs:28:10:28:10 | Entry | CompileTimeOperators.cs:36:9:38:9 | After {...} | 14 |
| CompileTimeOperators.cs:28:10:28:10 | Exceptional Exit | CompileTimeOperators.cs:28:10:28:10 | Exceptional Exit | 1 |
@@ -237,41 +237,41 @@
| CompileTimeOperators.cs:30:9:38:9 | After try {...} ... | CompileTimeOperators.cs:39:9:39:34 | After ...; | 7 |
| CompileTimeOperators.cs:40:9:40:11 | End: | CompileTimeOperators.cs:28:10:28:10 | Normal Exit | 9 |
| ConditionalAccess.cs:1:7:1:23 | Entry | ConditionalAccess.cs:1:7:1:23 | Exit | 11 |
-| ConditionalAccess.cs:3:12:3:13 | Entry | ConditionalAccess.cs:3:26:3:26 | access to parameter i | 4 |
+| ConditionalAccess.cs:3:12:3:13 | Entry | ConditionalAccess.cs:3:26:3:26 | access to parameter i | 5 |
| ConditionalAccess.cs:3:26:3:26 | After access to parameter i [non-null] | ConditionalAccess.cs:3:26:3:38 | call to method ToString | 2 |
| ConditionalAccess.cs:3:26:3:26 | After access to parameter i [null] | ConditionalAccess.cs:3:26:3:26 | After access to parameter i [null] | 1 |
| ConditionalAccess.cs:3:26:3:38 | After call to method ToString [non-null] | ConditionalAccess.cs:3:26:3:49 | call to method ToLower | 2 |
| ConditionalAccess.cs:3:26:3:38 | After call to method ToString [null] | ConditionalAccess.cs:3:26:3:38 | After call to method ToString [null] | 1 |
| ConditionalAccess.cs:3:26:3:49 | After call to method ToLower | ConditionalAccess.cs:3:12:3:13 | Exit | 3 |
-| ConditionalAccess.cs:5:10:5:11 | Entry | ConditionalAccess.cs:5:26:5:26 | access to parameter s | 3 |
+| ConditionalAccess.cs:5:10:5:11 | Entry | ConditionalAccess.cs:5:26:5:26 | access to parameter s | 4 |
| ConditionalAccess.cs:5:26:5:26 | After access to parameter s [non-null] | ConditionalAccess.cs:5:26:5:34 | access to property Length | 2 |
| ConditionalAccess.cs:5:26:5:26 | After access to parameter s [null] | ConditionalAccess.cs:5:26:5:26 | After access to parameter s [null] | 1 |
| ConditionalAccess.cs:5:26:5:34 | After access to property Length | ConditionalAccess.cs:5:10:5:11 | Exit | 3 |
-| ConditionalAccess.cs:7:10:7:11 | Entry | ConditionalAccess.cs:7:39:7:40 | access to parameter s1 | 4 |
+| ConditionalAccess.cs:7:10:7:11 | Entry | ConditionalAccess.cs:7:39:7:40 | access to parameter s1 | 6 |
| ConditionalAccess.cs:7:38:7:55 | After access to property Length | ConditionalAccess.cs:7:10:7:11 | Exit | 3 |
| ConditionalAccess.cs:7:39:7:40 | After access to parameter s1 [non-null] | ConditionalAccess.cs:7:39:7:40 | After access to parameter s1 [non-null] | 1 |
| ConditionalAccess.cs:7:39:7:40 | After access to parameter s1 [null] | ConditionalAccess.cs:7:45:7:46 | access to parameter s2 | 2 |
| ConditionalAccess.cs:7:39:7:46 | After ... ?? ... [non-null] | ConditionalAccess.cs:7:38:7:55 | access to property Length | 2 |
| ConditionalAccess.cs:7:45:7:46 | After access to parameter s2 [non-null] | ConditionalAccess.cs:7:45:7:46 | After access to parameter s2 [non-null] | 1 |
| ConditionalAccess.cs:7:45:7:46 | After access to parameter s2 [null] | ConditionalAccess.cs:7:39:7:46 | After ... ?? ... [null] | 2 |
-| ConditionalAccess.cs:9:9:9:10 | Entry | ConditionalAccess.cs:9:25:9:25 | access to parameter s | 4 |
+| ConditionalAccess.cs:9:9:9:10 | Entry | ConditionalAccess.cs:9:25:9:25 | access to parameter s | 5 |
| ConditionalAccess.cs:9:25:9:25 | After access to parameter s [non-null] | ConditionalAccess.cs:9:25:9:33 | access to property Length | 2 |
| ConditionalAccess.cs:9:25:9:25 | After access to parameter s [null] | ConditionalAccess.cs:9:25:9:25 | After access to parameter s [null] | 1 |
| ConditionalAccess.cs:9:25:9:33 | After access to property Length [non-null] | ConditionalAccess.cs:9:25:9:33 | After access to property Length [non-null] | 1 |
| ConditionalAccess.cs:9:25:9:33 | After access to property Length [null] | ConditionalAccess.cs:9:38:9:38 | 0 | 2 |
| ConditionalAccess.cs:9:25:9:38 | After ... ?? ... | ConditionalAccess.cs:9:9:9:10 | Exit | 3 |
-| ConditionalAccess.cs:11:9:11:10 | Entry | ConditionalAccess.cs:13:13:13:13 | access to parameter s | 6 |
+| ConditionalAccess.cs:11:9:11:10 | Entry | ConditionalAccess.cs:13:13:13:13 | access to parameter s | 7 |
| ConditionalAccess.cs:11:9:11:10 | Normal Exit | ConditionalAccess.cs:11:9:11:10 | Exit | 2 |
| ConditionalAccess.cs:13:13:13:13 | After access to parameter s [non-null] | ConditionalAccess.cs:13:13:13:21 | access to property Length | 2 |
| ConditionalAccess.cs:13:13:13:13 | After access to parameter s [null] | ConditionalAccess.cs:13:13:13:13 | After access to parameter s [null] | 1 |
| ConditionalAccess.cs:13:13:13:21 | After access to property Length | ConditionalAccess.cs:13:13:13:25 | ... > ... | 6 |
| ConditionalAccess.cs:13:13:13:25 | After ... > ... [false] | ConditionalAccess.cs:16:13:16:21 | return ...; | 4 |
| ConditionalAccess.cs:13:13:13:25 | After ... > ... [true] | ConditionalAccess.cs:14:13:14:21 | return ...; | 4 |
-| ConditionalAccess.cs:19:12:19:13 | Entry | ConditionalAccess.cs:19:40:19:41 | access to parameter s1 | 3 |
+| ConditionalAccess.cs:19:12:19:13 | Entry | ConditionalAccess.cs:19:40:19:41 | access to parameter s1 | 5 |
| ConditionalAccess.cs:19:40:19:41 | After access to parameter s1 [non-null] | ConditionalAccess.cs:19:40:19:60 | call to method CommaJoinWith | 3 |
| ConditionalAccess.cs:19:40:19:41 | After access to parameter s1 [null] | ConditionalAccess.cs:19:40:19:41 | After access to parameter s1 [null] | 1 |
| ConditionalAccess.cs:19:40:19:60 | After call to method CommaJoinWith | ConditionalAccess.cs:19:12:19:13 | Exit | 3 |
-| ConditionalAccess.cs:21:10:21:11 | Entry | ConditionalAccess.cs:23:18:23:29 | (...) ... | 9 |
+| ConditionalAccess.cs:21:10:21:11 | Entry | ConditionalAccess.cs:23:18:23:29 | (...) ... | 10 |
| ConditionalAccess.cs:23:17:23:38 | After access to property Length | ConditionalAccess.cs:24:18:24:24 | (...) ... | 11 |
| ConditionalAccess.cs:23:18:23:29 | After (...) ... [non-null] | ConditionalAccess.cs:23:17:23:38 | access to property Length | 2 |
| ConditionalAccess.cs:23:18:23:29 | After (...) ... [null] | ConditionalAccess.cs:23:18:23:29 | After (...) ... [null] | 1 |
@@ -281,14 +281,14 @@
| ConditionalAccess.cs:25:13:25:14 | After "" [non-null] | ConditionalAccess.cs:25:13:25:32 | call to method CommaJoinWith | 3 |
| ConditionalAccess.cs:25:13:25:14 | After "" [null] | ConditionalAccess.cs:25:13:25:14 | After "" [null] | 1 |
| ConditionalAccess.cs:25:13:25:32 | After call to method CommaJoinWith | ConditionalAccess.cs:21:10:21:11 | Exit | 7 |
-| ConditionalAccess.cs:30:10:30:12 | Entry | ConditionalAccess.cs:30:10:30:12 | Exit | 8 |
-| ConditionalAccess.cs:32:10:32:11 | Entry | ConditionalAccess.cs:35:9:35:12 | access to property Prop | 14 |
+| ConditionalAccess.cs:30:10:30:12 | Entry | ConditionalAccess.cs:30:10:30:12 | Exit | 9 |
+| ConditionalAccess.cs:32:10:32:11 | Entry | ConditionalAccess.cs:35:9:35:12 | access to property Prop | 16 |
| ConditionalAccess.cs:35:9:35:12 | After access to property Prop [non-null] | ConditionalAccess.cs:35:9:35:24 | call to method Out | 3 |
| ConditionalAccess.cs:35:9:35:12 | After access to property Prop [null] | ConditionalAccess.cs:35:9:35:12 | After access to property Prop [null] | 1 |
| ConditionalAccess.cs:35:9:35:24 | After call to method Out | ConditionalAccess.cs:32:10:32:11 | Exit | 5 |
-| ConditionalAccess.cs:42:9:42:11 | Entry | ConditionalAccess.cs:42:9:42:11 | Exit | 7 |
-| ConditionalAccess.cs:43:9:43:11 | Entry | ConditionalAccess.cs:43:9:43:11 | Exit | 4 |
-| ConditionalAccess.cs:46:10:46:11 | Entry | ConditionalAccess.cs:48:9:48:10 | access to parameter ca | 6 |
+| ConditionalAccess.cs:42:9:42:11 | Entry | ConditionalAccess.cs:42:9:42:11 | Exit | 8 |
+| ConditionalAccess.cs:43:9:43:11 | Entry | ConditionalAccess.cs:43:9:43:11 | Exit | 6 |
+| ConditionalAccess.cs:46:10:46:11 | Entry | ConditionalAccess.cs:48:9:48:10 | access to parameter ca | 7 |
| ConditionalAccess.cs:48:9:48:10 | After access to parameter ca [non-null] | ConditionalAccess.cs:48:12:48:25 | ... = ... | 5 |
| ConditionalAccess.cs:48:9:48:10 | After access to parameter ca [null] | ConditionalAccess.cs:48:9:48:10 | After access to parameter ca [null] | 1 |
| ConditionalAccess.cs:48:12:48:25 | After ... = ... | ConditionalAccess.cs:49:9:49:10 | access to parameter ca | 6 |
@@ -314,16 +314,16 @@
| ConditionalAccess.cs:54:9:54:10 | After access to parameter ca [non-null] | ConditionalAccess.cs:54:12:54:29 | ... += ... | 5 |
| ConditionalAccess.cs:54:9:54:10 | After access to parameter ca [null] | ConditionalAccess.cs:54:9:54:10 | After access to parameter ca [null] | 1 |
| ConditionalAccess.cs:54:12:54:29 | After ... += ... | ConditionalAccess.cs:46:10:46:11 | Exit | 5 |
-| ConditionalAccess.cs:60:26:60:38 | Entry | ConditionalAccess.cs:60:26:60:38 | Exit | 12 |
+| ConditionalAccess.cs:60:26:60:38 | Entry | ConditionalAccess.cs:60:26:60:38 | Exit | 14 |
| Conditions.cs:1:7:1:16 | Entry | Conditions.cs:1:7:1:16 | Exit | 11 |
-| Conditions.cs:3:10:3:19 | Entry | Conditions.cs:5:13:5:15 | access to parameter inc | 4 |
+| Conditions.cs:3:10:3:19 | Entry | Conditions.cs:5:13:5:15 | access to parameter inc | 6 |
| Conditions.cs:5:9:6:16 | After if (...) ... | Conditions.cs:7:14:7:16 | access to parameter inc | 4 |
| Conditions.cs:5:13:5:15 | After access to parameter inc [false] | Conditions.cs:5:13:5:15 | After access to parameter inc [false] | 1 |
| Conditions.cs:5:13:5:15 | After access to parameter inc [true] | Conditions.cs:6:13:6:16 | After ...; | 7 |
| Conditions.cs:7:9:8:16 | After if (...) ... | Conditions.cs:3:10:3:19 | Exit | 4 |
| Conditions.cs:7:14:7:16 | After access to parameter inc [false] | Conditions.cs:8:13:8:16 | After ...; | 8 |
| Conditions.cs:7:14:7:16 | After access to parameter inc [true] | Conditions.cs:7:13:7:16 | After !... [false] | 2 |
-| Conditions.cs:11:9:11:10 | Entry | Conditions.cs:14:13:14:13 | access to parameter b | 11 |
+| Conditions.cs:11:9:11:10 | Entry | Conditions.cs:14:13:14:13 | access to parameter b | 12 |
| Conditions.cs:14:9:15:16 | After if (...) ... | Conditions.cs:16:13:16:17 | ... > ... | 6 |
| Conditions.cs:14:13:14:13 | After access to parameter b [false] | Conditions.cs:14:13:14:13 | After access to parameter b [false] | 1 |
| Conditions.cs:14:13:14:13 | After access to parameter b [true] | Conditions.cs:15:13:15:16 | After ...; | 7 |
@@ -333,7 +333,7 @@
| Conditions.cs:17:13:18:20 | After if (...) ... | Conditions.cs:17:13:18:20 | After if (...) ... | 1 |
| Conditions.cs:17:18:17:18 | After access to parameter b [false] | Conditions.cs:18:17:18:20 | After ...; | 8 |
| Conditions.cs:17:18:17:18 | After access to parameter b [true] | Conditions.cs:17:17:17:18 | After !... [false] | 2 |
-| Conditions.cs:22:9:22:10 | Entry | Conditions.cs:25:13:25:14 | access to parameter b1 | 11 |
+| Conditions.cs:22:9:22:10 | Entry | Conditions.cs:25:13:25:14 | access to parameter b1 | 13 |
| Conditions.cs:25:9:27:20 | After if (...) ... | Conditions.cs:28:13:28:14 | access to parameter b2 | 3 |
| Conditions.cs:25:13:25:14 | After access to parameter b1 [false] | Conditions.cs:25:13:25:14 | After access to parameter b1 [false] | 1 |
| Conditions.cs:25:13:25:14 | After access to parameter b1 [true] | Conditions.cs:26:17:26:18 | access to parameter b2 | 3 |
@@ -343,7 +343,7 @@
| Conditions.cs:28:9:29:16 | After if (...) ... | Conditions.cs:22:9:22:10 | Exit | 6 |
| Conditions.cs:28:13:28:14 | After access to parameter b2 [false] | Conditions.cs:28:13:28:14 | After access to parameter b2 [false] | 1 |
| Conditions.cs:28:13:28:14 | After access to parameter b2 [true] | Conditions.cs:29:13:29:16 | After ...; | 7 |
-| Conditions.cs:33:9:33:10 | Entry | Conditions.cs:37:13:37:14 | access to parameter b1 | 18 |
+| Conditions.cs:33:9:33:10 | Entry | Conditions.cs:37:13:37:14 | access to parameter b1 | 19 |
| Conditions.cs:37:9:38:20 | After if (...) ... | Conditions.cs:39:13:39:14 | access to local variable b2 | 3 |
| Conditions.cs:37:13:37:14 | After access to parameter b1 [false] | Conditions.cs:37:13:37:14 | After access to parameter b1 [false] | 1 |
| Conditions.cs:37:13:37:14 | After access to parameter b1 [true] | Conditions.cs:38:13:38:20 | After ...; | 8 |
@@ -353,14 +353,14 @@
| Conditions.cs:41:9:42:16 | After if (...) ... | Conditions.cs:33:9:33:10 | Exit | 6 |
| Conditions.cs:41:13:41:14 | After access to local variable b2 [false] | Conditions.cs:41:13:41:14 | After access to local variable b2 [false] | 1 |
| Conditions.cs:41:13:41:14 | After access to local variable b2 [true] | Conditions.cs:42:13:42:16 | After ...; | 7 |
-| Conditions.cs:46:9:46:10 | Entry | Conditions.cs:49:9:53:9 | while (...) ... | 10 |
+| Conditions.cs:46:9:46:10 | Entry | Conditions.cs:49:9:53:9 | while (...) ... | 12 |
| Conditions.cs:49:9:53:9 | [LoopHeader] while (...) ... | Conditions.cs:49:16:49:22 | ... > ... | 8 |
| Conditions.cs:49:16:49:22 | After ... > ... [false] | Conditions.cs:46:9:46:10 | Exit | 7 |
| Conditions.cs:49:16:49:22 | After ... > ... [true] | Conditions.cs:51:17:51:17 | access to parameter b | 4 |
| Conditions.cs:51:13:52:20 | After if (...) ... | Conditions.cs:50:9:53:9 | After {...} | 2 |
| Conditions.cs:51:17:51:17 | After access to parameter b [false] | Conditions.cs:51:17:51:17 | After access to parameter b [false] | 1 |
| Conditions.cs:51:17:51:17 | After access to parameter b [true] | Conditions.cs:52:17:52:20 | After ...; | 7 |
-| Conditions.cs:57:9:57:10 | Entry | Conditions.cs:60:9:64:9 | while (...) ... | 10 |
+| Conditions.cs:57:9:57:10 | Entry | Conditions.cs:60:9:64:9 | while (...) ... | 12 |
| Conditions.cs:60:9:64:9 | [LoopHeader] while (...) ... | Conditions.cs:60:16:60:22 | ... > ... | 8 |
| Conditions.cs:60:16:60:22 | After ... > ... [false] | Conditions.cs:65:13:65:13 | access to parameter b | 4 |
| Conditions.cs:60:16:60:22 | After ... > ... [true] | Conditions.cs:62:17:62:17 | access to parameter b | 4 |
@@ -370,7 +370,7 @@
| Conditions.cs:65:9:66:16 | After if (...) ... | Conditions.cs:57:9:57:10 | Exit | 6 |
| Conditions.cs:65:13:65:13 | After access to parameter b [false] | Conditions.cs:65:13:65:13 | After access to parameter b [false] | 1 |
| Conditions.cs:65:13:65:13 | After access to parameter b [true] | Conditions.cs:66:13:66:16 | After ...; | 7 |
-| Conditions.cs:70:9:70:10 | Entry | Conditions.cs:74:27:74:28 | access to parameter ss | 25 |
+| Conditions.cs:70:9:70:10 | Entry | Conditions.cs:74:27:74:28 | access to parameter ss | 26 |
| Conditions.cs:74:9:80:9 | After foreach (... ... in ...) ... | Conditions.cs:81:13:81:13 | access to local variable b | 3 |
| Conditions.cs:74:22:74:22 | String _ | Conditions.cs:76:17:76:17 | access to local variable b | 4 |
| Conditions.cs:74:27:74:28 | After access to parameter ss [empty] | Conditions.cs:74:27:74:28 | After access to parameter ss [empty] | 1 |
@@ -384,7 +384,7 @@
| Conditions.cs:81:9:82:16 | After if (...) ... | Conditions.cs:70:9:70:10 | Exit | 6 |
| Conditions.cs:81:13:81:13 | After access to local variable b [false] | Conditions.cs:81:13:81:13 | After access to local variable b [false] | 1 |
| Conditions.cs:81:13:81:13 | After access to local variable b [true] | Conditions.cs:82:13:82:16 | After ...; | 7 |
-| Conditions.cs:86:9:86:10 | Entry | Conditions.cs:90:27:90:28 | access to parameter ss | 25 |
+| Conditions.cs:86:9:86:10 | Entry | Conditions.cs:90:27:90:28 | access to parameter ss | 26 |
| Conditions.cs:90:9:98:9 | After foreach (... ... in ...) ... | Conditions.cs:86:9:86:10 | Exit | 6 |
| Conditions.cs:90:22:90:22 | String _ | Conditions.cs:92:17:92:17 | access to local variable b | 4 |
| Conditions.cs:90:27:90:28 | After access to parameter ss [empty] | Conditions.cs:90:27:90:28 | After access to parameter ss [empty] | 1 |
@@ -398,7 +398,7 @@
| Conditions.cs:96:13:97:20 | After if (...) ... | Conditions.cs:90:9:98:9 | [LoopHeader] foreach (... ... in ...) ... | 3 |
| Conditions.cs:96:17:96:17 | After access to local variable b [false] | Conditions.cs:96:17:96:17 | After access to local variable b [false] | 1 |
| Conditions.cs:96:17:96:17 | After access to local variable b [true] | Conditions.cs:97:17:97:20 | After ...; | 7 |
-| Conditions.cs:102:12:102:13 | Entry | Conditions.cs:105:13:105:13 | access to parameter b | 14 |
+| Conditions.cs:102:12:102:13 | Entry | Conditions.cs:105:13:105:13 | access to parameter b | 15 |
| Conditions.cs:105:9:106:20 | After if (...) ... | Conditions.cs:107:13:107:24 | ... > ... | 9 |
| Conditions.cs:105:13:105:13 | After access to parameter b [false] | Conditions.cs:105:13:105:13 | After access to parameter b [false] | 1 |
| Conditions.cs:105:13:105:13 | After access to parameter b [true] | Conditions.cs:106:13:106:20 | After ...; | 8 |
@@ -408,7 +408,7 @@
| Conditions.cs:108:13:109:24 | After if (...) ... | Conditions.cs:108:13:109:24 | After if (...) ... | 1 |
| Conditions.cs:108:18:108:18 | After access to parameter b [false] | Conditions.cs:109:17:109:24 | After ...; | 9 |
| Conditions.cs:108:18:108:18 | After access to parameter b [true] | Conditions.cs:108:17:108:18 | After !... [false] | 2 |
-| Conditions.cs:113:10:113:11 | Entry | Conditions.cs:116:18:116:22 | After Int32 i = ... | 15 |
+| Conditions.cs:113:10:113:11 | Entry | Conditions.cs:116:18:116:22 | After Int32 i = ... | 16 |
| Conditions.cs:116:25:116:39 | After ... < ... [false] | Conditions.cs:113:10:113:11 | Exit | 5 |
| Conditions.cs:116:25:116:39 | After ... < ... [true] | Conditions.cs:119:18:119:21 | access to local variable last | 23 |
| Conditions.cs:116:25:116:39 | Before ... < ... | Conditions.cs:116:25:116:39 | ... < ... | 7 |
@@ -426,13 +426,21 @@
| Conditions.cs:135:17:138:17 | After if (...) ... | Conditions.cs:134:13:139:13 | After {...} | 2 |
| Conditions.cs:135:21:135:26 | After access to field Field2 [false] | Conditions.cs:135:21:135:26 | After access to field Field2 [false] | 1 |
| Conditions.cs:135:21:135:26 | After access to field Field2 [true] | Conditions.cs:136:17:138:17 | After {...} | 12 |
-| Conditions.cs:143:10:143:12 | Entry | Conditions.cs:145:17:145:17 | access to parameter b | 7 |
+| Conditions.cs:143:10:143:12 | Entry | Conditions.cs:145:17:145:17 | access to parameter b | 8 |
| Conditions.cs:145:17:145:17 | After access to parameter b [false] | Conditions.cs:145:27:145:29 | "b" | 2 |
| Conditions.cs:145:17:145:17 | After access to parameter b [true] | Conditions.cs:145:21:145:23 | "a" | 2 |
| Conditions.cs:145:17:145:29 | After ... ? ... : ... | Conditions.cs:146:13:146:13 | access to parameter b | 6 |
| Conditions.cs:146:9:149:49 | After if (...) ... | Conditions.cs:143:10:143:12 | Exit | 4 |
| Conditions.cs:146:13:146:13 | After access to parameter b [false] | Conditions.cs:149:13:149:49 | After ...; | 14 |
| Conditions.cs:146:13:146:13 | After access to parameter b [true] | Conditions.cs:147:13:147:49 | After ...; | 14 |
+| DefaultParam.cs:1:7:1:18 | Entry | DefaultParam.cs:1:7:1:18 | Exit | 11 |
+| DefaultParam.cs:3:12:3:13 | Entry | DefaultParam.cs:3:30:3:30 | s | 3 |
+| DefaultParam.cs:3:30:3:30 | After s [match] | DefaultParam.cs:3:30:3:30 | After s [match] | 1 |
+| DefaultParam.cs:3:30:3:30 | After s [no-match] | DefaultParam.cs:3:34:3:35 | "" | 2 |
+| DefaultParam.cs:3:42:3:42 | After i [match] | DefaultParam.cs:3:42:3:42 | After i [match] | 1 |
+| DefaultParam.cs:3:42:3:42 | After i [no-match] | DefaultParam.cs:3:46:3:46 | 0 | 2 |
+| DefaultParam.cs:3:42:3:42 | i | DefaultParam.cs:3:42:3:42 | i | 1 |
+| DefaultParam.cs:4:5:6:5 | {...} | DefaultParam.cs:3:12:3:13 | Exit | 20 |
| ExitMethods.cs:6:7:6:17 | Entry | ExitMethods.cs:6:7:6:17 | Exit | 11 |
| ExitMethods.cs:8:10:8:11 | Entry | ExitMethods.cs:8:10:8:11 | Exit | 12 |
| ExitMethods.cs:14:10:14:11 | Entry | ExitMethods.cs:14:10:14:11 | Exit | 12 |
@@ -448,11 +456,11 @@
| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | Exceptional Exit | 2 |
| ExitMethods.cs:54:10:54:11 | Entry | ExitMethods.cs:54:10:54:11 | Exit | 7 |
| ExitMethods.cs:60:10:60:11 | Entry | ExitMethods.cs:60:10:60:11 | Exit | 7 |
-| ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:68:13:68:13 | access to parameter b | 4 |
+| ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:68:13:68:13 | access to parameter b | 5 |
| ExitMethods.cs:66:17:66:26 | Exit | ExitMethods.cs:66:17:66:26 | Exit | 1 |
| ExitMethods.cs:68:13:68:13 | After access to parameter b [false] | ExitMethods.cs:66:17:66:26 | Normal Exit | 4 |
| ExitMethods.cs:68:13:68:13 | After access to parameter b [true] | ExitMethods.cs:66:17:66:26 | Exceptional Exit | 7 |
-| ExitMethods.cs:72:17:72:27 | Entry | ExitMethods.cs:74:13:74:13 | access to parameter b | 4 |
+| ExitMethods.cs:72:17:72:27 | Entry | ExitMethods.cs:74:13:74:13 | access to parameter b | 5 |
| ExitMethods.cs:72:17:72:27 | Exceptional Exit | ExitMethods.cs:72:17:72:27 | Exit | 2 |
| ExitMethods.cs:74:13:74:13 | After access to parameter b [false] | ExitMethods.cs:77:13:77:45 | throw ...; | 7 |
| ExitMethods.cs:74:13:74:13 | After access to parameter b [true] | ExitMethods.cs:75:13:75:34 | throw ...; | 6 |
@@ -464,29 +472,29 @@
| ExitMethods.cs:92:10:92:18 | Exit | ExitMethods.cs:92:10:92:18 | Exit | 1 |
| ExitMethods.cs:94:9:102:9 | After try {...} ... | ExitMethods.cs:92:10:92:18 | Normal Exit | 3 |
| ExitMethods.cs:105:10:105:24 | Entry | ExitMethods.cs:105:10:105:24 | Exit | 7 |
-| ExitMethods.cs:110:13:110:21 | Entry | ExitMethods.cs:112:16:112:25 | ... != ... | 11 |
+| ExitMethods.cs:110:13:110:21 | Entry | ExitMethods.cs:112:16:112:25 | ... != ... | 12 |
| ExitMethods.cs:110:13:110:21 | Exit | ExitMethods.cs:110:13:110:21 | Exit | 1 |
| ExitMethods.cs:112:16:112:25 | After ... != ... [false] | ExitMethods.cs:110:13:110:21 | Exceptional Exit | 8 |
| ExitMethods.cs:112:16:112:25 | After ... != ... [true] | ExitMethods.cs:110:13:110:21 | Normal Exit | 12 |
-| ExitMethods.cs:115:16:115:34 | Entry | ExitMethods.cs:117:16:117:30 | call to method Contains | 8 |
+| ExitMethods.cs:115:16:115:34 | Entry | ExitMethods.cs:117:16:117:30 | call to method Contains | 9 |
| ExitMethods.cs:117:16:117:30 | After call to method Contains [false] | ExitMethods.cs:117:38:117:38 | 1 | 2 |
| ExitMethods.cs:117:16:117:30 | After call to method Contains [true] | ExitMethods.cs:117:34:117:34 | 0 | 2 |
| ExitMethods.cs:117:16:117:38 | After ... ? ... : ... | ExitMethods.cs:115:16:115:34 | Exit | 4 |
| ExitMethods.cs:120:17:120:32 | Entry | ExitMethods.cs:120:17:120:32 | Exit | 8 |
| ExitMethods.cs:126:17:126:33 | Entry | ExitMethods.cs:126:17:126:33 | Exit | 8 |
-| ExitMethods.cs:132:10:132:20 | Entry | ExitMethods.cs:132:33:132:49 | call to method IsFalse | 4 |
+| ExitMethods.cs:132:10:132:20 | Entry | ExitMethods.cs:132:33:132:49 | call to method IsFalse | 5 |
| ExitMethods.cs:132:10:132:20 | Exceptional Exit | ExitMethods.cs:132:10:132:20 | Exceptional Exit | 1 |
| ExitMethods.cs:132:10:132:20 | Exit | ExitMethods.cs:132:10:132:20 | Exit | 1 |
| ExitMethods.cs:132:33:132:49 | After call to method IsFalse | ExitMethods.cs:132:10:132:20 | Normal Exit | 2 |
| ExitMethods.cs:134:17:134:33 | Entry | ExitMethods.cs:134:17:134:33 | Exit | 9 |
-| ExitMethods.cs:140:17:140:42 | Entry | ExitMethods.cs:142:13:142:13 | access to parameter b | 4 |
+| ExitMethods.cs:140:17:140:42 | Entry | ExitMethods.cs:142:13:142:13 | access to parameter b | 6 |
| ExitMethods.cs:140:17:140:42 | Exceptional Exit | ExitMethods.cs:140:17:140:42 | Exit | 2 |
| ExitMethods.cs:142:13:142:13 | After access to parameter b [false] | ExitMethods.cs:145:13:145:52 | call to method Throw | 8 |
| ExitMethods.cs:142:13:142:13 | After access to parameter b [true] | ExitMethods.cs:143:13:143:42 | call to method Throw | 5 |
-| Extensions.cs:5:23:5:29 | Entry | Extensions.cs:5:23:5:29 | Exit | 10 |
-| Extensions.cs:10:24:10:29 | Entry | Extensions.cs:10:24:10:29 | Exit | 11 |
+| Extensions.cs:5:23:5:29 | Entry | Extensions.cs:5:23:5:29 | Exit | 11 |
+| Extensions.cs:10:24:10:29 | Entry | Extensions.cs:10:24:10:29 | Exit | 13 |
| Extensions.cs:15:23:15:33 | Entry | Extensions.cs:15:23:15:33 | Exit | 7 |
-| Extensions.cs:20:17:20:20 | Entry | Extensions.cs:20:17:20:20 | Exit | 37 |
+| Extensions.cs:20:17:20:20 | Entry | Extensions.cs:20:17:20:20 | Exit | 38 |
| Finally.cs:3:14:3:20 | Entry | Finally.cs:3:14:3:20 | Exit | 11 |
| Finally.cs:7:10:7:11 | Entry | Finally.cs:11:13:11:37 | call to method WriteLine | 8 |
| Finally.cs:7:10:7:11 | Exceptional Exit | Finally.cs:7:10:7:11 | Exceptional Exit | 1 |
@@ -568,7 +576,7 @@
| Finally.cs:133:10:133:11 | Entry | Finally.cs:137:13:137:36 | call to method WriteLine | 8 |
| Finally.cs:137:13:137:36 | After call to method WriteLine | Finally.cs:136:9:138:9 | After {...} | 3 |
| Finally.cs:140:9:143:9 | {...} | Finally.cs:133:10:133:11 | Exit | 9 |
-| Finally.cs:147:10:147:11 | Entry | Finally.cs:151:17:151:28 | ... == ... | 9 |
+| Finally.cs:147:10:147:11 | Entry | Finally.cs:151:17:151:28 | ... == ... | 10 |
| Finally.cs:147:10:147:11 | Exceptional Exit | Finally.cs:147:10:147:11 | Exceptional Exit | 1 |
| Finally.cs:147:10:147:11 | Exit | Finally.cs:147:10:147:11 | Exit | 1 |
| Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:147:10:147:11 | Normal Exit | 3 |
@@ -589,7 +597,7 @@
| Finally.cs:172:11:172:20 | Entry | Finally.cs:172:11:172:20 | Exit | 11 |
| Finally.cs:173:11:173:20 | Entry | Finally.cs:173:11:173:20 | Exit | 11 |
| Finally.cs:174:11:174:20 | Entry | Finally.cs:174:11:174:20 | Exit | 11 |
-| Finally.cs:176:10:176:11 | Entry | Finally.cs:180:17:180:18 | access to parameter b1 | 6 |
+| Finally.cs:176:10:176:11 | Entry | Finally.cs:180:17:180:18 | access to parameter b1 | 8 |
| Finally.cs:176:10:176:11 | Exceptional Exit | Finally.cs:176:10:176:11 | Exceptional Exit | 1 |
| Finally.cs:176:10:176:11 | Exit | Finally.cs:176:10:176:11 | Exit | 1 |
| Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:176:10:176:11 | Normal Exit | 3 |
@@ -608,7 +616,7 @@
| Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | access to parameter b1 | 4 |
| Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:189:13:191:13 | After {...} | 3 |
| Finally.cs:190:21:190:22 | After access to parameter b1 [true] | Finally.cs:190:25:190:47 | throw ...; | 6 |
-| Finally.cs:195:10:195:12 | Entry | Finally.cs:199:17:199:18 | access to parameter b1 | 6 |
+| Finally.cs:195:10:195:12 | Entry | Finally.cs:199:17:199:18 | access to parameter b1 | 9 |
| Finally.cs:195:10:195:12 | Exceptional Exit | Finally.cs:195:10:195:12 | Exceptional Exit | 1 |
| Finally.cs:195:10:195:12 | Exit | Finally.cs:195:10:195:12 | Exit | 1 |
| Finally.cs:197:9:212:9 | After try {...} ... | Finally.cs:195:10:195:12 | Normal Exit | 13 |
@@ -627,7 +635,7 @@
| Finally.cs:220:13:220:36 | After call to method WriteLine | Finally.cs:219:9:221:9 | After {...} | 3 |
| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | After {...} | 10 |
| Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | Exit | 18 |
-| Finally.cs:233:10:233:12 | Entry | Finally.cs:239:21:239:22 | access to parameter b1 | 8 |
+| Finally.cs:233:10:233:12 | Entry | Finally.cs:239:21:239:22 | access to parameter b1 | 10 |
| Finally.cs:233:10:233:12 | Exceptional Exit | Finally.cs:233:10:233:12 | Exceptional Exit | 1 |
| Finally.cs:233:10:233:12 | Exit | Finally.cs:233:10:233:12 | Exit | 1 |
| Finally.cs:235:9:259:9 | After try {...} ... | Finally.cs:233:10:233:12 | Normal Exit | 9 |
@@ -643,24 +651,24 @@
| Finally.cs:250:17:252:17 | {...} | Finally.cs:250:17:252:17 | After {...} | 8 |
| Finally.cs:254:13:254:44 | After call to method WriteLine | Finally.cs:236:9:255:9 | After {...} | 3 |
| Finally.cs:257:9:259:9 | {...} | Finally.cs:257:9:259:9 | After {...} | 8 |
-| Finally.cs:263:10:263:12 | Entry | Finally.cs:267:13:267:34 | call to method WriteLine | 8 |
+| Finally.cs:263:10:263:12 | Entry | Finally.cs:267:13:267:34 | call to method WriteLine | 9 |
| Finally.cs:263:10:263:12 | Exceptional Exit | Finally.cs:263:10:263:12 | Exceptional Exit | 1 |
| Finally.cs:263:10:263:12 | Exit | Finally.cs:263:10:263:12 | Exit | 1 |
| Finally.cs:265:9:273:9 | After try {...} ... | Finally.cs:263:10:263:12 | Normal Exit | 3 |
| Finally.cs:267:13:267:34 | After call to method WriteLine | Finally.cs:266:9:268:9 | After {...} | 3 |
| Finally.cs:270:9:273:9 | {...} | Finally.cs:270:9:273:9 | After {...} | 15 |
| Foreach.cs:4:7:4:13 | Entry | Foreach.cs:4:7:4:13 | Exit | 11 |
-| Foreach.cs:6:10:6:11 | Entry | Foreach.cs:8:29:8:32 | access to parameter args | 4 |
+| Foreach.cs:6:10:6:11 | Entry | Foreach.cs:8:29:8:32 | access to parameter args | 5 |
| Foreach.cs:8:9:9:13 | After foreach (... ... in ...) ... | Foreach.cs:6:10:6:11 | Exit | 4 |
| Foreach.cs:8:22:8:24 | String arg | Foreach.cs:8:9:9:13 | [LoopHeader] foreach (... ... in ...) ... | 3 |
| Foreach.cs:8:29:8:32 | After access to parameter args [empty] | Foreach.cs:8:29:8:32 | After access to parameter args [empty] | 1 |
| Foreach.cs:8:29:8:32 | After access to parameter args [non-empty] | Foreach.cs:8:29:8:32 | After access to parameter args [non-empty] | 1 |
-| Foreach.cs:12:10:12:11 | Entry | Foreach.cs:14:27:14:30 | access to parameter args | 4 |
+| Foreach.cs:12:10:12:11 | Entry | Foreach.cs:14:27:14:30 | access to parameter args | 5 |
| Foreach.cs:14:9:15:13 | After foreach (... ... in ...) ... | Foreach.cs:12:10:12:11 | Exit | 4 |
| Foreach.cs:14:22:14:22 | String _ | Foreach.cs:14:9:15:13 | [LoopHeader] foreach (... ... in ...) ... | 3 |
| Foreach.cs:14:27:14:30 | After access to parameter args [empty] | Foreach.cs:14:27:14:30 | After access to parameter args [empty] | 1 |
| Foreach.cs:14:27:14:30 | After access to parameter args [non-empty] | Foreach.cs:14:27:14:30 | After access to parameter args [non-empty] | 1 |
-| Foreach.cs:18:10:18:11 | Entry | Foreach.cs:20:27:20:27 | access to parameter e | 6 |
+| Foreach.cs:18:10:18:11 | Entry | Foreach.cs:20:27:20:27 | access to parameter e | 7 |
| Foreach.cs:20:9:21:11 | After foreach (... ... in ...) ... | Foreach.cs:18:10:18:11 | Exit | 4 |
| Foreach.cs:20:22:20:22 | String x | Foreach.cs:20:9:21:11 | [LoopHeader] foreach (... ... in ...) ... | 3 |
| Foreach.cs:20:27:20:27 | After access to parameter e [non-null] | Foreach.cs:20:27:20:38 | call to method ToArray | 2 |
@@ -671,17 +679,17 @@
| Foreach.cs:20:27:20:68 | After ... ?? ... [non-empty] | Foreach.cs:20:27:20:68 | After ... ?? ... [non-empty] | 1 |
| Foreach.cs:20:43:20:68 | After call to method Empty [empty] | Foreach.cs:20:43:20:68 | After call to method Empty [empty] | 1 |
| Foreach.cs:20:43:20:68 | After call to method Empty [non-empty] | Foreach.cs:20:43:20:68 | After call to method Empty [non-empty] | 1 |
-| Foreach.cs:24:10:24:11 | Entry | Foreach.cs:26:36:26:39 | access to parameter args | 4 |
+| Foreach.cs:24:10:24:11 | Entry | Foreach.cs:26:36:26:39 | access to parameter args | 5 |
| Foreach.cs:26:9:27:11 | After foreach (... ... in ...) ... | Foreach.cs:24:10:24:11 | Exit | 4 |
| Foreach.cs:26:18:26:31 | Before (..., ...) | Foreach.cs:26:9:27:11 | [LoopHeader] foreach (... ... in ...) ... | 7 |
| Foreach.cs:26:36:26:39 | After access to parameter args [empty] | Foreach.cs:26:36:26:39 | After access to parameter args [empty] | 1 |
| Foreach.cs:26:36:26:39 | After access to parameter args [non-empty] | Foreach.cs:26:36:26:39 | After access to parameter args [non-empty] | 1 |
-| Foreach.cs:30:10:30:11 | Entry | Foreach.cs:32:32:32:35 | access to parameter args | 4 |
+| Foreach.cs:30:10:30:11 | Entry | Foreach.cs:32:32:32:35 | access to parameter args | 5 |
| Foreach.cs:32:9:33:11 | After foreach (... ... in ...) ... | Foreach.cs:30:10:30:11 | Exit | 4 |
| Foreach.cs:32:18:32:27 | Before (..., ...) | Foreach.cs:32:9:33:11 | [LoopHeader] foreach (... ... in ...) ... | 7 |
| Foreach.cs:32:32:32:35 | After access to parameter args [empty] | Foreach.cs:32:32:32:35 | After access to parameter args [empty] | 1 |
| Foreach.cs:32:32:32:35 | After access to parameter args [non-empty] | Foreach.cs:32:32:32:35 | After access to parameter args [non-empty] | 1 |
-| Foreach.cs:36:10:36:11 | Entry | Foreach.cs:38:39:38:42 | access to parameter args | 4 |
+| Foreach.cs:36:10:36:11 | Entry | Foreach.cs:38:39:38:42 | access to parameter args | 5 |
| Foreach.cs:38:9:39:11 | After foreach (... ... in ...) ... | Foreach.cs:36:10:36:11 | Exit | 4 |
| Foreach.cs:38:18:38:34 | Before (..., ...) | Foreach.cs:38:9:39:11 | [LoopHeader] foreach (... ... in ...) ... | 7 |
| Foreach.cs:38:39:38:42 | After access to parameter args [empty] | Foreach.cs:38:39:38:42 | After access to parameter args [empty] | 1 |
@@ -689,19 +697,19 @@
| Initializers.cs:3:7:3:18 | Entry | Initializers.cs:3:7:3:18 | Exit | 9 |
| Initializers.cs:3:7:3:18 | Entry | Initializers.cs:3:7:3:18 | Exit | 27 |
| Initializers.cs:8:5:8:16 | Entry | Initializers.cs:8:5:8:16 | Exit | 11 |
-| Initializers.cs:10:5:10:16 | Entry | Initializers.cs:10:5:10:16 | Exit | 11 |
+| Initializers.cs:10:5:10:16 | Entry | Initializers.cs:10:5:10:16 | Exit | 12 |
| Initializers.cs:12:10:12:10 | Entry | Initializers.cs:12:10:12:10 | Exit | 48 |
| Initializers.cs:20:11:20:23 | Entry | Initializers.cs:20:11:20:23 | Exit | 11 |
| Initializers.cs:20:11:20:23 | Entry | Initializers.cs:20:11:20:23 | Exit | 19 |
| Initializers.cs:26:11:26:13 | Entry | Initializers.cs:26:11:26:13 | Exit | 11 |
| Initializers.cs:31:9:31:11 | Entry | Initializers.cs:31:9:31:11 | Exit | 22 |
-| Initializers.cs:33:9:33:11 | Entry | Initializers.cs:33:9:33:11 | Exit | 18 |
-| Initializers.cs:35:9:35:11 | Entry | Initializers.cs:35:9:35:11 | Exit | 26 |
+| Initializers.cs:33:9:33:11 | Entry | Initializers.cs:33:9:33:11 | Exit | 19 |
+| Initializers.cs:35:9:35:11 | Entry | Initializers.cs:35:9:35:11 | Exit | 28 |
| Initializers.cs:39:7:39:23 | Entry | Initializers.cs:39:7:39:23 | Exit | 11 |
| Initializers.cs:41:11:41:18 | Entry | Initializers.cs:41:11:41:18 | Exit | 11 |
-| Initializers.cs:51:10:51:13 | Entry | Initializers.cs:51:10:51:13 | Exit | 245 |
+| Initializers.cs:51:10:51:13 | Entry | Initializers.cs:51:10:51:13 | Exit | 246 |
| LoopUnrolling.cs:5:7:5:19 | Entry | LoopUnrolling.cs:5:7:5:19 | Exit | 11 |
-| LoopUnrolling.cs:7:10:7:11 | Entry | LoopUnrolling.cs:9:13:9:28 | ... == ... | 10 |
+| LoopUnrolling.cs:7:10:7:11 | Entry | LoopUnrolling.cs:9:13:9:28 | ... == ... | 11 |
| LoopUnrolling.cs:7:10:7:11 | Normal Exit | LoopUnrolling.cs:7:10:7:11 | Exit | 2 |
| LoopUnrolling.cs:9:13:9:28 | After ... == ... [false] | LoopUnrolling.cs:11:29:11:32 | access to parameter args | 4 |
| LoopUnrolling.cs:9:13:9:28 | After ... == ... [true] | LoopUnrolling.cs:10:13:10:19 | return ...; | 3 |
@@ -714,7 +722,7 @@
| LoopUnrolling.cs:18:22:18:22 | String x | LoopUnrolling.cs:18:9:19:33 | [LoopHeader] foreach (... ... in ...) ... | 8 |
| LoopUnrolling.cs:18:27:18:28 | After access to local variable xs [empty] | LoopUnrolling.cs:18:27:18:28 | After access to local variable xs [empty] | 1 |
| LoopUnrolling.cs:18:27:18:28 | After access to local variable xs [non-empty] | LoopUnrolling.cs:18:27:18:28 | After access to local variable xs [non-empty] | 1 |
-| LoopUnrolling.cs:22:10:22:11 | Entry | LoopUnrolling.cs:24:29:24:32 | access to parameter args | 4 |
+| LoopUnrolling.cs:22:10:22:11 | Entry | LoopUnrolling.cs:24:29:24:32 | access to parameter args | 5 |
| LoopUnrolling.cs:24:9:26:40 | After foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | Exit | 4 |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:34:25:37 | access to parameter args | 3 |
| LoopUnrolling.cs:24:29:24:32 | After access to parameter args [empty] | LoopUnrolling.cs:24:29:24:32 | After access to parameter args [empty] | 1 |
@@ -741,7 +749,7 @@
| LoopUnrolling.cs:48:27:48:28 | After access to local variable xs [empty] | LoopUnrolling.cs:45:10:45:11 | Exit | 5 |
| LoopUnrolling.cs:48:27:48:28 | After access to local variable xs [non-empty] | LoopUnrolling.cs:49:9:52:9 | {...} | 3 |
| LoopUnrolling.cs:50:9:50:13 | Label: | LoopUnrolling.cs:51:13:51:23 | goto ...; | 9 |
-| LoopUnrolling.cs:55:10:55:11 | Entry | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | 20 |
+| LoopUnrolling.cs:55:10:55:11 | Entry | LoopUnrolling.cs:58:27:58:28 | access to local variable xs | 21 |
| LoopUnrolling.cs:58:9:64:9 | After foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | Exit | 4 |
| LoopUnrolling.cs:58:22:58:22 | String x | LoopUnrolling.cs:60:17:60:17 | access to parameter b | 4 |
| LoopUnrolling.cs:58:27:58:28 | After access to local variable xs [empty] | LoopUnrolling.cs:58:27:58:28 | After access to local variable xs [empty] | 1 |
@@ -752,7 +760,7 @@
| LoopUnrolling.cs:62:13:63:37 | After if (...) ... | LoopUnrolling.cs:58:9:64:9 | [LoopHeader] foreach (... ... in ...) ... | 3 |
| LoopUnrolling.cs:62:17:62:17 | After access to parameter b [false] | LoopUnrolling.cs:62:17:62:17 | After access to parameter b [false] | 1 |
| LoopUnrolling.cs:62:17:62:17 | After access to parameter b [true] | LoopUnrolling.cs:63:17:63:37 | After ...; | 7 |
-| LoopUnrolling.cs:67:10:67:11 | Entry | LoopUnrolling.cs:69:14:69:23 | call to method Any | 7 |
+| LoopUnrolling.cs:67:10:67:11 | Entry | LoopUnrolling.cs:69:14:69:23 | call to method Any | 8 |
| LoopUnrolling.cs:67:10:67:11 | Normal Exit | LoopUnrolling.cs:67:10:67:11 | Exit | 2 |
| LoopUnrolling.cs:69:14:69:23 | After call to method Any [false] | LoopUnrolling.cs:70:13:70:19 | return ...; | 4 |
| LoopUnrolling.cs:69:14:69:23 | After call to method Any [true] | LoopUnrolling.cs:72:29:72:32 | access to parameter args | 11 |
@@ -784,7 +792,7 @@
| MultiImplementationA.cs:7:21:7:23 | Entry | MultiImplementationA.cs:7:21:7:23 | Entry | 1 |
| MultiImplementationA.cs:7:21:7:23 | Exit | MultiImplementationA.cs:7:21:7:23 | Exit | 1 |
| MultiImplementationA.cs:7:25:7:39 | {...} | MultiImplementationA.cs:7:21:7:23 | Exceptional Exit | 5 |
-| MultiImplementationA.cs:7:41:7:43 | Entry | MultiImplementationA.cs:7:41:7:43 | Entry | 1 |
+| MultiImplementationA.cs:7:41:7:43 | Entry | MultiImplementationA.cs:7:41:7:43 | value | 2 |
| MultiImplementationA.cs:7:41:7:43 | Exit | MultiImplementationA.cs:7:41:7:43 | Exit | 1 |
| MultiImplementationA.cs:7:45:7:59 | {...} | MultiImplementationA.cs:7:41:7:43 | Exceptional Exit | 5 |
| MultiImplementationA.cs:8:16:8:16 | Entry | MultiImplementationA.cs:8:16:8:16 | Entry | 1 |
@@ -793,21 +801,21 @@
| MultiImplementationA.cs:11:7:11:8 | Entry | MultiImplementationA.cs:11:7:11:8 | Entry | 1 |
| MultiImplementationA.cs:11:7:11:8 | Normal Exit | MultiImplementationA.cs:11:7:11:8 | Exit | 2 |
| MultiImplementationA.cs:13:16:13:20 | Before ... = ... | MultiImplementationA.cs:24:32:24:34 | After ... = ... | 16 |
-| MultiImplementationA.cs:14:31:14:31 | Entry | MultiImplementationA.cs:14:31:14:31 | Entry | 1 |
+| MultiImplementationA.cs:14:31:14:31 | Entry | MultiImplementationA.cs:14:25:14:25 | i | 2 |
| MultiImplementationA.cs:14:31:14:31 | Exit | MultiImplementationA.cs:14:31:14:31 | Exit | 1 |
| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | Normal Exit | 2 |
-| MultiImplementationA.cs:15:36:15:38 | Entry | MultiImplementationA.cs:15:36:15:38 | Entry | 1 |
+| MultiImplementationA.cs:15:36:15:38 | Entry | MultiImplementationA.cs:15:31:15:31 | s | 2 |
| MultiImplementationA.cs:15:36:15:38 | Exit | MultiImplementationA.cs:15:36:15:38 | Exit | 1 |
| MultiImplementationA.cs:15:40:15:52 | {...} | MultiImplementationA.cs:15:36:15:38 | Normal Exit | 5 |
-| MultiImplementationA.cs:15:54:15:56 | Entry | MultiImplementationA.cs:15:54:15:56 | Entry | 1 |
+| MultiImplementationA.cs:15:54:15:56 | Entry | MultiImplementationA.cs:15:54:15:56 | value | 3 |
| MultiImplementationA.cs:15:54:15:56 | Normal Exit | MultiImplementationA.cs:15:54:15:56 | Exit | 2 |
| MultiImplementationA.cs:15:58:15:60 | {...} | MultiImplementationA.cs:15:58:15:60 | {...} | 1 |
-| MultiImplementationA.cs:16:17:16:18 | Entry | MultiImplementationA.cs:16:17:16:18 | Entry | 1 |
+| MultiImplementationA.cs:16:17:16:18 | Entry | MultiImplementationA.cs:16:24:16:24 | i | 2 |
| MultiImplementationA.cs:16:17:16:18 | Normal Exit | MultiImplementationA.cs:16:17:16:18 | Exit | 2 |
| MultiImplementationA.cs:17:5:19:5 | {...} | MultiImplementationA.cs:17:5:19:5 | After {...} | 3 |
| MultiImplementationA.cs:18:9:18:22 | Entry | MultiImplementationA.cs:18:9:18:22 | Exit | 4 |
| MultiImplementationA.cs:20:12:20:13 | Before call to method